Skip to content
Snippets Groups Projects
Commit 1ac0459c authored by Viktor Popov's avatar Viktor Popov
Browse files

Updated handler implementation nad tests

parent 10619cca
No related branches found
No related tags found
1 merge request!140-key-storage-service-api
......@@ -18,7 +18,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package handler
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"io"
"log"
"math/big"
"strings"
"time"
"code.vereign.com/code/viam-apis/versions"
"github.com/golang/protobuf/proto"
......@@ -53,90 +62,252 @@ func (s *KeyStorageServerImpl) CreateAuthentication(ctx context.Context) *authen
return nil
}
func (s *KeyStorageServerImpl) GetPrivateKey(ctx context.Context, in *api.GetPrivateKeyRequest) (*api.GetPrivateKeyResponse, error) {
func (s *KeyStorageServerImpl) GetKey(ctx context.Context, in *api.GetKeyRequest) (*api.GetKeyResponse, error) {
auth := s.CreateAuthentication(ctx)
client := &client.DataStorageClientImpl{}
client.SetUpClient(auth, s.DataStorageUrl, s.CertPath)
defer client.CloseClient()
data, _ := client.DoGetDataCall("privatekeys", in.Name)
getKeyResponse := &api.GetKeyResponse{}
getPrivateKeyResponse := &api.GetPrivateKeyResponse{}
if in.KeyType == api.KeyType_KT_EMPTY {
getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList, "400", api.StatusType_ERROR, "KeyType cannot be empty")
}
data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType))
if data.Errors != "" {
getPrivateKeyResponse.Key = nil
getPrivateKeyResponse.StatusList = utils.AddStatus(getPrivateKeyResponse.StatusList, "500", "Internal server error", data.Errors)
getKeyResponse.Key = nil
getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList, "500", api.StatusType_ERROR, data.Errors)
} else {
key := &api.PrivateKey{}
key := &api.Key{}
proto.Unmarshal(data.Data.Data, key)
getPrivateKeyResponse.Key = key
getKeyResponse.Key = key
}
return getPrivateKeyResponse, nil
return getKeyResponse, nil
}
func (s *KeyStorageServerImpl) GetPublicKey(ctx context.Context, in *api.GetPublicKeyRequest) (*api.GetPublicKeyResponse, error) {
func (s *KeyStorageServerImpl) SetKey(ctx context.Context, in *api.SetKeyRequest) (*api.SetKeyResponse, error) {
auth := s.CreateAuthentication(ctx)
client := &client.DataStorageClientImpl{}
client.SetUpClient(auth, s.DataStorageUrl, s.CertPath)
defer client.CloseClient()
data, _ := client.DoGetDataCall("publickeys", in.Name)
setKeyResponse := &api.SetKeyResponse{}
if in.KeyType == api.KeyType_KT_EMPTY {
setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, "400", api.StatusType_ERROR, "KeyType cannot be empty")
}
getPublicKeyResponse := &api.GetPublicKeyResponse{}
data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType))
if data.Errors != "" {
getPublicKeyResponse.Key = nil
getPublicKeyResponse.StatusList = utils.AddStatus(getPublicKeyResponse.StatusList, "500", "Internal server error", data.Errors)
} else {
key := &api.PublicKey{}
proto.Unmarshal(data.Data.Data, key)
getPublicKeyResponse.Key = key
setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, "400", api.StatusType_ERROR, data.Errors)
return setKeyResponse, nil
}
return getPublicKeyResponse, nil
result, errors, err := client.DoPutDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType), in.Key, versions.EntitiesManagementAgentApiVersion)
setKeyResponse.StatusList = handlePutDataErrors(setKeyResponse.StatusList, errors, err)
if setKeyResponse.StatusList == nil || len(setKeyResponse.StatusList) == 0 {
setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, "200", api.StatusType_INFO, result)
}
return setKeyResponse, nil
}
func (s *KeyStorageServerImpl) SetPrivateKey(ctx context.Context, in *api.SetPrivateKeyRequest) (*api.SetPrivateKeyResponse, error) {
func (s *KeyStorageServerImpl) GenerateKeyPair(ctx context.Context, in *api.GenerateKeyPairRequest) (*api.GenerateKeyPairResponse, error) {
auth := s.CreateAuthentication(ctx)
client := &client.DataStorageClientImpl{}
client.SetUpClient(auth, s.DataStorageUrl, s.CertPath)
defer client.CloseClient()
result, errors, err := client.DoPutDataCall("privatekeys", in.Key.Name, in.Key, versions.EntitiesManagementAgentApiVersion)
uuid, err := newUUID()
privateKeyBytes, publicKeyBytes, _ := generateKeyPair(int(in.KeySize * 8))
setPrivateKeyResponse := &api.SetPrivateKeyResponse{}
if err != nil {
setPrivateKeyResponse.StatusList = utils.AddStatus(setPrivateKeyResponse.StatusList, "500", "error", err.Error())
} else if errors != "" {
setPrivateKeyResponse.StatusList = utils.AddStatus(setPrivateKeyResponse.StatusList, "500", "error", errors)
privateKey := &api.Key{Content: privateKeyBytes}
publicKey := &api.Key{Content: publicKeyBytes}
generateKeyPairResponse := &api.GenerateKeyPairResponse{
Uuid: uuid,
}
result, errors, err := client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE), privateKey, versions.EntitiesManagementAgentApiVersion)
generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err)
if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 {
result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC), publicKey, versions.EntitiesManagementAgentApiVersion)
generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err)
}
if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 {
generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList, "200", api.StatusType_INFO, result)
}
return generateKeyPairResponse, nil
}
func (s *KeyStorageServerImpl) GenerateCertificate(ctx context.Context, in *api.GenerateCertificateRequest) (*api.GenerateCertificateResponse, error) {
auth := s.CreateAuthentication(ctx)
client := &client.DataStorageClientImpl{}
client.SetUpClient(auth, s.DataStorageUrl, s.CertPath)
defer client.CloseClient()
generateCertificateResponse := &api.GenerateCertificateResponse{}
privateKeyMessage := &api.Key{}
publicKeyMessage := &api.Key{}
data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE))
if data.Errors != "" {
generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, "400", api.StatusType_ERROR, data.Errors)
} else {
proto.Unmarshal(data.Data.Data, privateKeyMessage)
}
data, _ = client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC))
if data.Errors != "" {
generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, "400", api.StatusType_ERROR, data.Errors)
} else {
setPrivateKeyResponse.StatusList = utils.AddStatus(setPrivateKeyResponse.StatusList, "200", "info", result)
proto.Unmarshal(data.Data.Data, publicKeyMessage)
}
certificateBytes, err := generateCertificate(privateKeyMessage.Content, publicKeyMessage.Content, in.CertificateData)
if err != nil {
generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, "400", api.StatusType_ERROR, err.Error())
}
certificateMessage := &api.Key{
Content: certificateBytes,
}
result, errors, err := client.DoPutDataCall("keys", in.Uuid+"/"+api.KeyType.String(api.KeyType_CERTIFICATE), certificateMessage, versions.EntitiesManagementAgentApiVersion)
generateCertificateResponse.StatusList = handlePutDataErrors(generateCertificateResponse.StatusList, errors, err)
if generateCertificateResponse.StatusList == nil || len(generateCertificateResponse.StatusList) == 0 {
generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, "200", api.StatusType_INFO, result)
}
return setPrivateKeyResponse, nil
return generateCertificateResponse, nil
}
func (s *KeyStorageServerImpl) SetPublicKey(ctx context.Context, in *api.SetPublicKeyRequest) (*api.SetPublicKeyResponse, error) {
func (s *KeyStorageServerImpl) ReserveKeyUUID(ctx context.Context, in *api.ReserveKeyUUIDRequest) (*api.ReserveKeyUUIDResponse, error) {
auth := s.CreateAuthentication(ctx)
client := &client.DataStorageClientImpl{}
client.SetUpClient(auth, s.DataStorageUrl, s.CertPath)
defer client.CloseClient()
result, errors, err := client.DoPutDataCall("publickeys", in.Key.Name, in.Key, versions.EntitiesManagementAgentApiVersion)
uuid, err := newUUID()
emptyKey := &api.Key{
Content: []byte{},
}
reserveKeyUUIDResponse := &api.ReserveKeyUUIDResponse{
Uuid: uuid,
}
result, errors, err := client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE), emptyKey, versions.EntitiesManagementAgentApiVersion)
reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC), emptyKey, versions.EntitiesManagementAgentApiVersion)
reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
}
if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_CERTIFICATE), emptyKey, versions.EntitiesManagementAgentApiVersion)
reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
}
if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList, "200", api.StatusType_INFO, result)
}
setPublicKeyResponse := &api.SetPublicKeyResponse{}
return reserveKeyUUIDResponse, nil
}
func generateKeyPair(bitSize int) ([]byte, []byte, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, bitSize)
if err != nil {
return nil, nil, err
}
err = privateKey.Validate()
if err != nil {
setPublicKeyResponse.StatusList = utils.AddStatus(setPublicKeyResponse.StatusList, "500", "error", err.Error())
return nil, nil, err
}
publicKey := &privateKey.PublicKey
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
publicKeyBytes := x509.MarshalPKCS1PublicKey(publicKey)
return privateKeyBytes, publicKeyBytes, nil
}
func generateCertificate(privateKeyBytes []byte, publicKeyBytes []byte, certificateData *api.GenerateCertificateRequest_CertificateData) ([]byte, error) {
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBytes)
if err != nil {
return nil, err
}
publicKey, err := x509.ParsePKCS1PublicKey(publicKeyBytes)
if err != nil {
return nil, err
}
notBeforeTime := time.Unix(certificateData.NotBefore.Seconds, int64(certificateData.NotBefore.Nanos)).UTC()
notAfterTime := time.Unix(certificateData.NotAfter.Seconds, int64(certificateData.NotAfter.Nanos)).UTC()
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
Country: []string{certificateData.Country},
Organization: []string{certificateData.Organization},
OrganizationalUnit: []string{certificateData.OrganizationalUnit},
CommonName: certificateData.CommonName,
},
NotBefore: notBeforeTime,
NotAfter: notAfterTime,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
IsCA: true,
DNSNames: []string{certificateData.Host},
}
certificateBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey, privateKey)
if err != nil {
log.Fatalf("Failed to create certificate: %s", err)
}
return certificateBytes, nil
}
func newUUID() (string, error) {
uuid := make([]byte, 16)
n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil {
return "", err
}
uuid[8] = uuid[8]&^0xc0 | 0x80
uuid[6] = uuid[6]&^0xf0 | 0x40
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}
func handlePutDataErrors(statusList []*api.Status, errors string, err error) []*api.Status {
if err != nil {
statusList = utils.AddStatus(statusList, "500", api.StatusType_ERROR, err.Error())
} else if errors != "" {
setPublicKeyResponse.StatusList = utils.AddStatus(setPublicKeyResponse.StatusList, "500", "error", errors)
} else {
setPublicKeyResponse.StatusList = utils.AddStatus(setPublicKeyResponse.StatusList, "200", "info", result)
statusList = utils.AddStatus(statusList, "400", api.StatusType_ERROR, errors)
}
return setPublicKeyResponse, nil
return statusList
}
......@@ -28,6 +28,7 @@ import (
"code.vereign.com/code/viam-apis/authentication"
ksapi "code.vereign.com/code/viam-apis/key-storage-agent/api"
ksclient "code.vereign.com/code/viam-apis/key-storage-agent/client"
timestamp "github.com/golang/protobuf/ptypes/timestamp"
)
const (
......@@ -51,56 +52,147 @@ func TestSetAndGetKeys(t *testing.T) {
keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFile)
defer keyStorageClient.CloseClient()
privateKey := &ksapi.PrivateKey{
Name: "privkey1",
PublicKeyReference: "pubkey1",
Content: []byte{0, 1, 4},
uuid, statusList, _ := keyStorageClient.DoReserveKeyUUID()
for _, status := range statusList {
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoReserveKeyUUID, returned error: %s.", status.Code+":"+status.Description)
}
}
privateKey := &ksapi.Key{
Content: []byte{0, 1, 4},
}
statusList, _ := keyStorageClient.DoSetPrivateKey(privateKey)
statusList, _ = keyStorageClient.DoSetKey(uuid, ksapi.KeyType_PRIVATE, privateKey)
for _, status := range statusList {
if status.StatusType == "error" {
t.Errorf("DoSetPrivateKey, returned error: %s.", status.Code+":"+status.Description)
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoSetKey, returned error: %s.", status.Code+":"+status.Description)
return
}
}
privateKeyResult, statusList, _ := keyStorageClient.DoGetPrivateKey("privkey1")
privateKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PRIVATE)
for _, status := range statusList {
if status.StatusType == "error" {
t.Errorf("DoGetPrivateKey, returned error: %s.", status.Code+":"+status.Description)
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
return
}
}
if privateKeyResult.Content == nil || !utils.CompareByteArrays(privateKeyResult.Content, []byte{0, 1, 4}) {
t.Errorf("DoGetPrivateKey, incorrect keyResult.Content, expected: %v, but was: %v",
t.Errorf("DoGetKey, incorrect keyResult.Content, expected: %v, but was: %v",
[]byte{0, 1, 2}, privateKeyResult.Content)
}
publicKey := &ksapi.PublicKey{
Name: "pubkey1",
Content: []byte{3, 4, 2},
Certificate: []byte{5, 1, 6},
publicKey := &ksapi.Key{
Content: []byte{3, 4, 2},
}
statusList, _ = keyStorageClient.DoSetPublicKey(publicKey)
statusList, _ = keyStorageClient.DoSetKey(uuid, ksapi.KeyType_PUBLIC, publicKey)
for _, status := range statusList {
if status.StatusType == "error" {
t.Errorf("DoSetPublicKey, returned error: %s.", status.Code+":"+status.Description)
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoSetKey, returned error: %s.", status.Code+":"+status.Description)
}
}
publicKeyResult, statusList, _ := keyStorageClient.DoGetPublicKey("pubkey1")
publicKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PUBLIC)
for _, status := range statusList {
if status.StatusType == "error" {
t.Errorf("DoGetPublicKey, returned error: %s.", status.Code+":"+status.Description)
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
}
}
if publicKeyResult.Content == nil || !utils.CompareByteArrays(publicKeyResult.Content, []byte{3, 4, 2}) {
t.Errorf("DoGetPublicKey, incorrect publicKeyResult.Content, expected: %v, but was: %v",
t.Errorf("DoGetKey, incorrect publicKeyResult.Content, expected: %v, but was: %v",
[]byte{3, 4, 2}, publicKeyResult.Content)
}
if publicKeyResult.Certificate == nil || !utils.CompareByteArrays(publicKeyResult.Certificate, []byte{5, 1, 6}) {
t.Errorf("DoGetPublicKey, incorrect publicKeyResult.Certificate, expected: %v, but was: %v",
[]byte{5, 1, 6}, publicKeyResult.Certificate)
}
func TestGenerateKeyPairAndCertificate(t *testing.T) {
dataStorageClient := utils.CreateClientFromUuidAndSession("viam-system", "viam-session", dataStorageGrpcAddress, certFile)
keyStorageAuth := &authentication.Authentication{
Uuid: "some-uuid",
Session: "some-session",
}
_, _, _ = dataStorageClient.RenewSession(keyStorageAuth.Uuid, keyStorageAuth.Session)
keyStorageClient := &ksclient.KeyStorageClientImpl{}
keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFile)
defer keyStorageClient.CloseClient()
uuid, statusList, _ := keyStorageClient.DoGenerateKeyPair(256)
for _, status := range statusList {
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoGenerateKeyPair, returned error: %s.", status.Code+":"+status.Description)
return
}
}
if uuid == "" {
t.Errorf("DoGenerateKeyPair, uuid is empty")
return
}
privateKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PRIVATE)
for _, status := range statusList {
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
return
}
}
if privateKeyResult.Content == nil {
t.Errorf("DoGetKey, privateKeyResult.Content is nil")
}
publicKeyResult, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_PUBLIC)
for _, status := range statusList {
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
return
}
}
if publicKeyResult.Content == nil {
t.Errorf("DoGetKey, publicKeyResult.Content is nil")
}
nowTime := time.Now()
nowTimeSeconds := time.Now().Unix()
nowTimeNanoSeconds := int32(nowTime.Sub(time.Unix(nowTimeSeconds, 0)))
notBefore := &timestamp.Timestamp{
Seconds: nowTimeSeconds,
Nanos: nowTimeNanoSeconds,
}
timeAfterOneDay := nowTime.Add(1000000 * 3600 * 24)
secondsAfterOneDay := time.Now().Unix()
nanoSecondsAfterOneDay := int32(timeAfterOneDay.Sub(time.Unix(secondsAfterOneDay, 0)))
notAfter := &timestamp.Timestamp{
Seconds: secondsAfterOneDay,
Nanos: nanoSecondsAfterOneDay,
}
certificateData := &ksapi.GenerateCertificateRequest_CertificateData{
Country: "BG",
Organization: "company",
OrganizationalUnit: "DEV",
CommonName: "CN",
NotBefore: notBefore,
NotAfter: notAfter,
Host: "abcde.com",
}
statusList, _ = keyStorageClient.DoGenerateCertificate(uuid, certificateData)
for _, status := range statusList {
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoGenerateCertificate, returned error: %s.", status.Code+":"+status.Description)
}
}
certificate, statusList, _ := keyStorageClient.DoGetKey(uuid, ksapi.KeyType_CERTIFICATE)
for _, status := range statusList {
if status.StatusType == ksapi.StatusType_ERROR {
t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description)
}
}
if certificate.Content == nil {
t.Errorf("DoGetKey, certificate.Content is nil")
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment