diff --git a/cert/vereign_ca.cer b/cert/vereign_ca.cer new file mode 100644 index 0000000000000000000000000000000000000000..6aacfac5ee9a0c352d35ebc86d9e3a4ee848841d --- /dev/null +++ b/cert/vereign_ca.cer @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEnjCCA4agAwIBAgIEW2lRSjANBgkqhkiG9w0BAQsFADCBoTETMBEGCgmSJomT +8ixkARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB3ZlcmVpZ24xCzAJBgNVBAYTAkJH +MRAwDgYDVQQIDAdQbG92ZGl2MRAwDgYDVQQHDAdQbG92ZGl2MRMwEQYDVQQKDApW +ZXJlaWduIEFHMRUwEwYDVQQLDAxWZXJlaWduIExhYnMxFDASBgNVBAMMC3ZlcmVp +Z24uY29tMB4XDTE4MDgwNzA3NTkwNloXDTI4MDgwNzA3NTkwNlowgaExEzARBgoJ +kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgd2ZXJlaWduMQswCQYDVQQG +EwJCRzEQMA4GA1UECAwHUGxvdmRpdjEQMA4GA1UEBwwHUGxvdmRpdjETMBEGA1UE +CgwKVmVyZWlnbiBBRzEVMBMGA1UECwwMVmVyZWlnbiBMYWJzMRQwEgYDVQQDDAt2 +ZXJlaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALYs0VOg +HyXuNbJhYjZBLKoR2EH95VYQ5BStX+KD7ppxlT+H4sxbuj11xVVcDj95aJvlc9Nc +yBdWktjkIi+MrqoiMM1ljuCzwSsvfnVidWGhZmqSNvEjXgAkX57NoG0U+C9AK16i +otLApBQ79sXSONfxq2fbdXlaGm98ahCLreomFqKXizkTsOmnirbouJvTX0eFXeaA ++qXPhGpsQxu7vOlWoWqgCAqPAn2krpIBKPvX8n9rL29tFs8JXft0Z5MKykCweP8D +Sn3e4nmMUDRl8F/0+r+1HIK5FWw2vKUrinMAN/YkpsfEE/flIlZCKg3D8GEYnMFQ +w9Gaz7NVH87qI8sCAwEAAaOB2zCB2DAeBgNVHREEFzAVgRNjb250YWN0QHZlcmVp +Z24uY29tMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MIGaBgNVHSUEgZIwgY8G +CCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCisGAQQBgjcKAwwGCSqGSIb3 +LwEBBQYIKwYBBQUHAwQGCisGAQQBgjcKAwQGCCsGAQUFBwMFBggrBgEFBQcDBgYI +KwYBBQUHAwcGCCsGAQUFBwMIBggrBgEFBQcDCQYKKwYBBAGCNxQCAgYEVR0lADAN +BgkqhkiG9w0BAQsFAAOCAQEAMotIWeKzq8T2CZR6hzUMVjBzLfJRnKKXLwoaa3R0 +mXwOcyloQmIQkYqQ7M4ELDEmAtN/f7cE/uBhUdD8UEWn0I4Im6Al8Q7eUFPOAvW3 +uvoqEx5+0sMjsBDUxVW1xkcwYIP9Vpp7occ4Uu0dbj6WR6jsTWQFor+Fc+J4wkRq +5a4i7pnI78r41rJAHpIUqToLmcoxBOqVrjDys/scCQcxlDGgZcy7T4OFGgJGUdY0 +Zs2W/7GdZUKctb4d+2kWwvA+34w8V9lOBTwM2ddSYS/EkUYMkP93Cb0/LH9Go43u +U2lEx/41yecR4bipRcwHamTOlvpsFoC9+NjZ0m+l9EM0vA== +-----END CERTIFICATE----- diff --git a/cert/vereign_ca.key b/cert/vereign_ca.key new file mode 100644 index 0000000000000000000000000000000000000000..2bdd81dff19a2917475fa8845923b4021ce475f3 --- /dev/null +++ b/cert/vereign_ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2LNFToB8l7jWy +YWI2QSyqEdhB/eVWEOQUrV/ig+6acZU/h+LMW7o9dcVVXA4/eWib5XPTXMgXVpLY +5CIvjK6qIjDNZY7gs8ErL351YnVhoWZqkjbxI14AJF+ezaBtFPgvQCteoqLSwKQU +O/bF0jjX8atn23V5WhpvfGoQi63qJhail4s5E7Dpp4q26Lib019HhV3mgPqlz4Rq +bEMbu7zpVqFqoAgKjwJ9pK6SASj71/J/ay9vbRbPCV37dGeTCspAsHj/A0p93uJ5 +jFA0ZfBf9Pq/tRyCuRVsNrylK4pzADf2JKbHxBP35SJWQioNw/BhGJzBUMPRms+z +VR/O6iPLAgMBAAECggEAG9HMRZD2MLynxo3IibB6OZ5v/+Pd2b7Klb3EHrs2/K7L +s9/0anC3iBsr/1UHd/n6V5Q6k9RfWfEGi8iKz+gT5DdEbJlNsFLC9O1Tymk2s6oK +EcwyR7C28h6b24xbK01AeTa7aMA9TSHN7KkbjioENDXbjwicb+OqlcvSBqTN8iuM +aZrpLHG1ddd7qceUsJuZWkrtC8/RIv/OOPbjdCx2US24T1AgpSANgReHWqk2C8aK +Bo/Np2NhKKr0lmWN7mhXKBV/OVtM8QPFd8JfsI4vQByd3aV0R5GJpBgX/sP2rQi5 +CnZSV45f6OrYNbzK3DgNdVLFqFUdvAdyroyClTDQgQKBgQDzm6WnmjKg20wUi3tb +Wy7syU8Ss4WBFeCjt5aVkqeILgdeMwy+FBnXZNfU5enNBTjPMRcAfPuVm0jet79H +NLgHrTU80sb5fQ0fENlS031OOdEG0PjeoCCGfGsf/YFsmS2WYSHlkYlbibItCmzn +WTVmu0KIQ3H82YDqz7vu/NQ0WQKBgQC/cSsdwPrMVT1XcSANB77/81v2t3ZVrckx +gp1KNWKEmaVgWfFsNQ780d4HQAdhKAa9eKRLAL3R7hIDOGXSTPkxEZ95LwkzbNlf +qSnlxTwhRY41+OHYdjHMzCTu8qoumwPLCrFkKBdU/s5z84HA8KU1nAIAJzz1mNAN +qbT+Bv/kwwKBgCTSV/23bwOlYiCQ3Lp4U+VyoEMhY4KZffUBIP/GxQ/udSql6L0q +aKWIFp+ViPt2WJnov6NRQO3iJOeVOpJWw6JVagChk3XOkxcpAtBkK0KRtqijGZr8 +9S2ezMpvFQsHND7Qu8DpeKufapEoTEHD2DCJCYtzNl2TusrDT5LWIHUxAoGADCwe +6LJnf+x/jPrFZe6zJ0UK+OHrZUE6hKpgY+KHFBVM3ZZ6cj3haRPTATUCAxxvaUat +c5Nlfl6byJaiar+4LHWJZUQnWpy2KY3w+woSa68nfqkHeyLwwavNQWAuj+4NTLCu +XMbrzNyytc6q1mC2sHTt76KPDrKbr/K1bl11kc8CgYEAodKJD6bP4w1vWDR08/HU +T4I0XaKq5X150BbwQZO0axEsuiVwqsosioXYSVAW85NOWSTNDSgpVPCjyWRyHyRL +cVVrWMQda3Hc/s6EzsiqC0BGw9D0r3TZN8n7Wm+BoNkek//xPhoiLfNTKtwRZIcr +CikzGE28ynzRwrDK70wV7Q4= +-----END PRIVATE KEY----- diff --git a/handler/generate_certificate.go b/handler/generate_certificate.go new file mode 100644 index 0000000000000000000000000000000000000000..e4d6dba8143d4d16fcef6f6f3cf45f2aead8c02d --- /dev/null +++ b/handler/generate_certificate.go @@ -0,0 +1,244 @@ +/* +Copyright (c) 2018 Vereign AG [https://www.vereign.com] + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package handler + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "io/ioutil" + "math/big" + "time" + + "code.vereign.com/code/viam-apis/data-storage-agent/client" + "code.vereign.com/code/viam-apis/key-storage-agent/api" + "code.vereign.com/code/viam-apis/utils" + "code.vereign.com/code/viam-apis/versions" + "github.com/golang/protobuf/proto" + "golang.org/x/net/context" +) + +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.CertFilePath) + defer client.CloseClient() + + generateCertificateResponse := &api.GenerateCertificateResponse{} + + // Get and decrypt aes key + encryptedAesKeyMessage := &api.Key{} + data, _ := client.DoGetDataCall("keys", in.Uuid+"/aeskey") + if data.Errors != "" { + generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, + "400", api.StatusType_ERROR, data.Errors) + return generateCertificateResponse, nil + } + + proto.Unmarshal(data.Data.Data, encryptedAesKeyMessage) + + aesKeyBytes, err := rsaDecryptWithServerKey(s.VereignPrivateKeyFilePath, encryptedAesKeyMessage.Content, []byte("aeskeys")) + if err != nil { + generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, + "400", api.StatusType_ERROR, err.Error()) + return generateCertificateResponse, nil + } + + // Get and decrypt rsa private key + encryptedPrivateKeyMessage := &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) + return generateCertificateResponse, nil + } + proto.Unmarshal(data.Data.Data, encryptedPrivateKeyMessage) + + nonce := &api.Key{} + data, _ = client.DoGetDataCall("keys", in.Uuid+"/privatekey_nonce") + if data.Errors != "" { + generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, + "400", api.StatusType_ERROR, data.Errors) + return generateCertificateResponse, nil + } + proto.Unmarshal(data.Data.Data, nonce) + + privateKeyBytes, err := aesDecrypt(aesKeyBytes, nonce.Content, encryptedPrivateKeyMessage.Content) + if err != nil { + generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, + "400", api.StatusType_ERROR, err.Error()) + return generateCertificateResponse, nil + } + + // Get and decrypt rsa public key + encryptedPublicKeyMessage := &api.Key{} + 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) + return generateCertificateResponse, nil + } + proto.Unmarshal(data.Data.Data, encryptedPublicKeyMessage) + + nonce = &api.Key{} + data, _ = client.DoGetDataCall("keys", in.Uuid+"/publickey_nonce") + if data.Errors != "" { + generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, + "400", api.StatusType_ERROR, data.Errors) + return generateCertificateResponse, nil + } + proto.Unmarshal(data.Data.Data, nonce) + + publicKeyBytes, err := aesDecrypt(aesKeyBytes, nonce.Content, encryptedPublicKeyMessage.Content) + if err != nil { + generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, + "400", api.StatusType_ERROR, err.Error()) + return generateCertificateResponse, nil + } + + certificateBytes, err := generateCertificate(privateKeyBytes, publicKeyBytes, s.VereignCertFilePath, in.CertificateData) + if err != nil { + generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, + "400", api.StatusType_ERROR, err.Error()) + return generateCertificateResponse, nil + } + + 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 generateCertificateResponse, nil +} + +func generateCertificate(privateKeyBytes []byte, publicKeyBytes []byte, caCertFilePath string, + certificateData *api.GenerateCertificateRequest_CertificateData) ([]byte, error) { + + privateKey, err := x509.ParsePKCS8PrivateKey(privateKeyBytes) + if err != nil { + return nil, err + } + publicKey, err := x509.ParsePKIXPublicKey(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: false, + DNSNames: []string{certificateData.Host}, + } + + caCertificate, err := readCertificateFromFile(caCertFilePath) + if err != nil { + return nil, err + } + + certificateBytes, err := x509.CreateCertificate(rand.Reader, &template, caCertificate, publicKey, privateKey) + if err != nil { + return nil, err + } + + return certificateBytes, nil +} + +func readPrivateKeyFromFile(fileName string) (*rsa.PrivateKey, error) { + privateKeyPemBlock, err := readPemBlockFromFile(fileName) + if err != nil { + return nil, err + } + + parseResult, err := x509.ParsePKCS8PrivateKey(privateKeyPemBlock.Bytes) + if err != nil { + return nil, err + } + privateKey := parseResult.(*rsa.PrivateKey) + + return privateKey, nil +} + +func readPemBlockFromFile(fileName string) (*pem.Block, error) { + fileBytes, err := ioutil.ReadFile(fileName) + if err != nil { + return nil, err + } + + certificatePemBlock, _ := pem.Decode(fileBytes) + + return certificatePemBlock, nil +} + +func rsaDecryptWithServerKey(privateKeyFilePath string, encryptedMessage []byte, label []byte) ([]byte, error) { + serverPrivateKey, err := readPrivateKeyFromFile(privateKeyFilePath) + if err != nil { + return nil, err + } + + message, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, serverPrivateKey, encryptedMessage, label) + if err != nil { + return nil, err + } + + return message, nil +} + +func aesDecrypt(aesKey []byte, nonce []byte, encryptedMessage []byte) ([]byte, error) { + block, err := aes.NewCipher(aesKey) + if err != nil { + return nil, err + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + message, err := aesgcm.Open(nil, nonce, encryptedMessage, nil) + if err != nil { + return nil, err + } + + return message, nil +} diff --git a/handler/generate_keypair.go b/handler/generate_keypair.go new file mode 100644 index 0000000000000000000000000000000000000000..8e2ef25340faad611d2d58c4eb5a5d20b081aacd --- /dev/null +++ b/handler/generate_keypair.go @@ -0,0 +1,186 @@ +/* +Copyright (c) 2018 Vereign AG [https://www.vereign.com] + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package handler + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + + "code.vereign.com/code/viam-apis/data-storage-agent/client" + "code.vereign.com/code/viam-apis/key-storage-agent/api" + "code.vereign.com/code/viam-apis/utils" + "code.vereign.com/code/viam-apis/versions" + "golang.org/x/net/context" +) + +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.CertFilePath) + defer client.CloseClient() + + generateKeyPairResponse := &api.GenerateKeyPairResponse{} + + uuid, err := generateUnusedUUID(client) + if err != nil { + generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList, + "500", api.StatusType_ERROR, err.Error()) + } + + privateKeyBytes, publicKeyBytes, err := generateKeyPair(int(in.KeySize)) + if err != nil { + generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList, + "500", api.StatusType_ERROR, err.Error()) + } + + aesKeyBytes, err := generateRandomSequence(256) + if err != nil { + generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList, + "500", api.StatusType_ERROR, err.Error()) + } + encryptedAesKeyBytes, err := rsaEncryptWithServerKey(s.VereignCertFilePath, aesKeyBytes, []byte("aeskeys")) + if err != nil { + generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList, + "500", api.StatusType_ERROR, err.Error()) + return generateKeyPairResponse, nil + } + + encryptedAesKey := &api.Key{Content: encryptedAesKeyBytes} + + result, errors, err := client.DoPutDataCall("keys", uuid+"/aeskey", encryptedAesKey, versions.EntitiesManagementAgentApiVersion) + generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err) + + if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 { + encryptedPrivateKeyBytes, nonce, err := aesEncrypt(aesKeyBytes, privateKeyBytes) + if err != nil { + generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList, + "500", api.StatusType_ERROR, err.Error()) + return generateKeyPairResponse, nil + } + encryptedPrivateKey := &api.Key{Content: encryptedPrivateKeyBytes} + result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE), encryptedPrivateKey, versions.EntitiesManagementAgentApiVersion) + generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err) + if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 { + nonceMessage := &api.Key{Content: nonce} + result, errors, err = client.DoPutDataCall("keys", uuid+"/privatekey_nonce", nonceMessage, versions.EntitiesManagementAgentApiVersion) + generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err) + } + } + + if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 { + encryptedPublicKeyBytes, nonce, err := aesEncrypt(aesKeyBytes, publicKeyBytes) + if err != nil { + generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList, + "500", api.StatusType_ERROR, err.Error()) + return generateKeyPairResponse, nil + } + encryptedPublicKey := &api.Key{Content: encryptedPublicKeyBytes} + result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC), encryptedPublicKey, versions.EntitiesManagementAgentApiVersion) + generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err) + if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 { + nonceMessage := &api.Key{Content: nonce} + result, errors, err = client.DoPutDataCall("keys", uuid+"/publickey_nonce", nonceMessage, versions.EntitiesManagementAgentApiVersion) + generateKeyPairResponse.StatusList = handlePutDataErrors(generateKeyPairResponse.StatusList, errors, err) + } + } + + if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 { + generateKeyPairResponse.Uuid = uuid + generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList, + "200", api.StatusType_INFO, result) + } + + return generateKeyPairResponse, nil +} + +func generateKeyPair(keySize int) ([]byte, []byte, error) { + privateKey, err := rsa.GenerateKey(rand.Reader, keySize) + if err != nil { + return nil, nil, err + } + + err = privateKey.Validate() + if err != nil { + return nil, nil, err + } + + publicKey := &privateKey.PublicKey + + privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey) + if err != nil { + return nil, nil, err + } + publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey) + if err != nil { + return nil, nil, err + } + + return privateKeyBytes, publicKeyBytes, nil +} + +func rsaEncryptWithServerKey(certFilePath string, message []byte, label []byte) ([]byte, error) { + serverCertificate, err := readCertificateFromFile(certFilePath) + if err != nil { + return nil, err + } + serverPublicKey := serverCertificate.PublicKey.(*rsa.PublicKey) + + encryptedMessageBytes, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, serverPublicKey, message, label) + if err != nil { + return nil, err + } + + return encryptedMessageBytes, nil +} + +func aesEncrypt(aesKey []byte, message []byte) ([]byte, []byte, error) { + block, err := aes.NewCipher(aesKey) + if err != nil { + return nil, nil, err + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, nil, err + } + + nonce, err := generateRandomSequence(aesgcm.NonceSize() * 8) + if err != nil { + return nil, nil, err + } + + encryptedMessage := aesgcm.Seal(nil, nonce, message, nil) + + return encryptedMessage, nonce, nil +} + +func generateRandomSequence(keySize int) ([]byte, error) { + key := make([]byte, keySize/8) + + _, err := rand.Read(key) + if err != nil { + return nil, err + } + + return key, nil +} diff --git a/handler/handler.go b/handler/handler.go index 99000df4702e059355e5444d5c76d8022edccf13..293a3408d8ed1346e9a112df4d0d895f0cce61aa 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -18,16 +18,7 @@ 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" @@ -42,8 +33,10 @@ import ( // Server represents the gRPC server type KeyStorageServerImpl struct { - DataStorageUrl string - CertPath string + DataStorageUrl string + CertFilePath string + VereignCertFilePath string + VereignPrivateKeyFilePath string } func (s *KeyStorageServerImpl) CreateAuthentication(ctx context.Context) *authentication.Authentication { @@ -66,20 +59,22 @@ func (s *KeyStorageServerImpl) GetKey(ctx context.Context, in *api.GetKeyRequest auth := s.CreateAuthentication(ctx) client := &client.DataStorageClientImpl{} - client.SetUpClient(auth, s.DataStorageUrl, s.CertPath) + client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath) defer client.CloseClient() getKeyResponse := &api.GetKeyResponse{} if in.KeyType == api.KeyType_KT_EMPTY { - getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList, "400", api.StatusType_ERROR, "KeyType cannot be 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 != "" { getKeyResponse.Key = nil - getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList, "500", api.StatusType_ERROR, data.Errors) + getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList, + "500", api.StatusType_ERROR, data.Errors) } else { key := &api.Key{} proto.Unmarshal(data.Data.Data, key) @@ -93,19 +88,29 @@ func (s *KeyStorageServerImpl) SetKey(ctx context.Context, in *api.SetKeyRequest auth := s.CreateAuthentication(ctx) client := &client.DataStorageClientImpl{} - client.SetUpClient(auth, s.DataStorageUrl, s.CertPath) + client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath) defer client.CloseClient() setKeyResponse := &api.SetKeyResponse{} if in.KeyType == api.KeyType_KT_EMPTY { - setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, "400", api.StatusType_ERROR, "KeyType cannot be empty") + setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, + "400", api.StatusType_ERROR, "KeyType cannot be empty") } data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType)) if data.Errors != "" { - setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, "400", api.StatusType_ERROR, data.Errors) + setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, + "400", api.StatusType_ERROR, data.Errors) + return setKeyResponse, nil + } + + key := &api.Key{} + proto.Unmarshal(data.Data.Data, key) + if key != nil && key.Content != nil && len(key.Content) > 0 { + setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, + "400", api.StatusType_ERROR, "Key is already set") return setKeyResponse, nil } @@ -113,105 +118,32 @@ func (s *KeyStorageServerImpl) SetKey(ctx context.Context, in *api.SetKeyRequest 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) + setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList, + "200", api.StatusType_INFO, result) } return setKeyResponse, nil } -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() - - uuid, err := newUUID() - privateKeyBytes, publicKeyBytes, _ := generateKeyPair(int(in.KeySize * 8)) - - 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) { +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) + client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath) 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 { - proto.Unmarshal(data.Data.Data, publicKeyMessage) - } + reserveKeyUUIDResponse := &api.ReserveKeyUUIDResponse{} - certificateBytes, err := generateCertificate(privateKeyMessage.Content, publicKeyMessage.Content, in.CertificateData) + uuid, err := generateUnusedUUID(client) if err != nil { - generateCertificateResponse.StatusList = utils.AddStatus(generateCertificateResponse.StatusList, "400", api.StatusType_ERROR, err.Error()) + reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList, + "500", api.StatusType_INFO, 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 generateCertificateResponse, nil -} - -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() - - 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) @@ -226,88 +158,10 @@ func (s *KeyStorageServerImpl) ReserveKeyUUID(ctx context.Context, in *api.Reser } if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 { - reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList, "200", api.StatusType_INFO, result) + reserveKeyUUIDResponse.Uuid = uuid + reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList, + "200", api.StatusType_INFO, result) } 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 { - 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 != "" { - statusList = utils.AddStatus(statusList, "400", api.StatusType_ERROR, errors) - } - - return statusList -} diff --git a/handler/revoke.go b/handler/revoke.go new file mode 100644 index 0000000000000000000000000000000000000000..2b779ed3372b1ef99fa2ba7d12823a8596386d84 --- /dev/null +++ b/handler/revoke.go @@ -0,0 +1,79 @@ +/* +Copyright (c) 2018 Vereign AG [https://www.vereign.com] + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package handler + +import ( + "code.vereign.com/code/viam-apis/data-storage-agent/client" + "code.vereign.com/code/viam-apis/key-storage-agent/api" + "code.vereign.com/code/viam-apis/utils" + "code.vereign.com/code/viam-apis/versions" + "github.com/golang/protobuf/proto" + "golang.org/x/net/context" +) + +func (s *KeyStorageServerImpl) Revoke(ctx context.Context, in *api.RevokeRequest) (*api.RevokeResponse, error) { + auth := s.CreateAuthentication(ctx) + + client := &client.DataStorageClientImpl{} + client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath) + defer client.CloseClient() + + revokeResponse := &api.RevokeResponse{} + + revokeResponse.StatusList = revokeKey(client, in.Uuid, api.KeyType_PRIVATE) + if revokeResponse.StatusList != nil { + return revokeResponse, nil + } + + revokeResponse.StatusList = revokeKey(client, in.Uuid, api.KeyType_PUBLIC) + if revokeResponse.StatusList != nil { + return revokeResponse, nil + } + + revokeResponse.StatusList = revokeKey(client, in.Uuid, api.KeyType_CERTIFICATE) + if revokeResponse.StatusList != nil { + return revokeResponse, nil + } + + revokeResponse.StatusList = utils.AddStatus(revokeResponse.StatusList, "200", api.StatusType_INFO, "Keys revoked") + return revokeResponse, nil +} + +func revokeKey(client *client.DataStorageClientImpl, uuid string, keyType api.KeyType) []*api.Status { + + statusList := []*api.Status{} + + data, _ := client.DoGetDataCall("keys", uuid+"/"+api.KeyType.String(keyType)) + if data.Errors != "" { + statusList = utils.AddStatus(statusList, "400", api.StatusType_ERROR, data.Errors) + return statusList + } + + key := &api.Key{} + proto.Unmarshal(data.Data.Data, key) + + key.Revoked = true + + _, errors, err := client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(keyType), key, versions.EntitiesManagementAgentApiVersion) + statusList = handlePutDataErrors(statusList, errors, err) + if statusList != nil && len(statusList) > 0 { + return statusList + } + + return nil +} diff --git a/handler/utils.go b/handler/utils.go new file mode 100644 index 0000000000000000000000000000000000000000..a489edca30ce359b8bf3431d6faced0b2797c520 --- /dev/null +++ b/handler/utils.go @@ -0,0 +1,85 @@ +/* +Copyright (c) 2018 Vereign AG [https://www.vereign.com] + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package handler + +import ( + "crypto/rand" + "crypto/x509" + "errors" + "fmt" + "io" + + "code.vereign.com/code/viam-apis/data-storage-agent/client" + "code.vereign.com/code/viam-apis/key-storage-agent/api" + "code.vereign.com/code/viam-apis/utils" +) + +func generateUnusedUUID(client *client.DataStorageClientImpl) (string, error) { + count := 0 + for { + uuid, err := newUUID() + + // check that uuid is not used + data, _ := client.DoGetDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE)) + + if data.Errors != "" || err != nil { + return uuid, nil + } + if count >= 10 { + return "", errors.New("Could not generate unused UUID in 10 tries") + } + count++ + } +} + +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 != "" { + statusList = utils.AddStatus(statusList, "400", api.StatusType_ERROR, errors) + } + + return statusList +} + +func readCertificateFromFile(fileName string) (*x509.Certificate, error) { + certificatePemBlock, err := readPemBlockFromFile(fileName) + if err != nil { + return nil, err + } + + certificate, err := x509.ParseCertificate(certificatePemBlock.Bytes) + if err != nil { + return nil, err + } + + return certificate, nil +} diff --git a/main.go b/main.go index 8cadaaafeb8faa93c0a0383cadb741b23c9a615a..0ed788dfa721c3818628fccaee0d525e01a7c1b3 100644 --- a/main.go +++ b/main.go @@ -39,12 +39,15 @@ func main() { restAddress := fmt.Sprintf("%s:%d", "localhost", 7878) dataStorageAddress := fmt.Sprintf("%s:%d", "localhost", 7777) - certFile := certDir + "/server.crt" - keyFile := certDir + "/server.key" + certFilePath := certDir + "/server.crt" + privateKeyFilePath := certDir + "/server.key" + vereignCertFilePath := certDir + "/vereign_ca.cer" + vereignPrivateKeyFilePath := certDir + "/vereign_ca.key" // fire the gRPC server in a goroutine go func() { - err := server.StartGRPCServer(grpcAddress, certFile, keyFile, dataStorageAddress) + err := server.StartGRPCServer(grpcAddress, certFilePath, privateKeyFilePath, vereignCertFilePath, + vereignPrivateKeyFilePath, dataStorageAddress) if err != nil { log.Fatalf("failed to start gRPC server: %s", err) } @@ -52,7 +55,7 @@ func main() { // fire the REST server in a goroutine go func() { - err := server.StartRESTServer(restAddress, grpcAddress, certFile) + err := server.StartRESTServer(restAddress, grpcAddress, certFilePath) if err != nil { log.Fatalf("failed to start gRPC server: %s", err) } diff --git a/server/server.go b/server/server.go index fa6892a8ba25068b898872887bdca0f0940a8d20..40e6a427ae6e7f8f8a88598daba917a20cf12029 100644 --- a/server/server.go +++ b/server/server.go @@ -106,8 +106,8 @@ func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServ return handler1(ctx, req) } -func StartGRPCServer(address, certFile, keyFile, dataStorageAddress string) error { - pkgCertFile = certFile +func StartGRPCServer(address, certFilePath, privateKeyFilePath, vereignCertFilePath, vereignPrivateKeyFilePath, dataStorageAddress string) error { + pkgCertFile = certFilePath // create a listener on TCP port lis, err := net.Listen("tcp", address) @@ -117,12 +117,14 @@ func StartGRPCServer(address, certFile, keyFile, dataStorageAddress string) erro // create a server instance s := handler.KeyStorageServerImpl{ - DataStorageUrl: dataStorageAddress, - CertPath: certFile, + DataStorageUrl: dataStorageAddress, + CertFilePath: certFilePath, + VereignCertFilePath: vereignCertFilePath, + VereignPrivateKeyFilePath: vereignPrivateKeyFilePath, } // Create the TLS credentials - creds, err := credentials.NewServerTLSFromFile(certFile, keyFile) + creds, err := credentials.NewServerTLSFromFile(certFilePath, privateKeyFilePath) if err != nil { return fmt.Errorf("could not load TLS keys: %s", err) } diff --git a/server/server_test.go b/server/server_test.go index 42c383b5e849f108af2c4b727ebd2a83f845c517..33f1aa4d0e21242e0f5dc38e3b171c25c5b12147 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -32,14 +32,16 @@ import ( ) const ( - dataStorageGrpcAddress = "localhost:7777" - keyStorageGrpcAddress = "localhost:7877" - certFile = "../cert/server.crt" - keyFile = "../cert/server.key" + dataStorageGrpcAddress = "localhost:7777" + keyStorageGrpcAddress = "localhost:7877" + certFilePath = "../cert/server.crt" + privateKeyFilePath = "../cert/server.key" + vereignCertFilePath = "../cert/vereign_ca.cer" + vereignPrivateKeyFilePath = "../cert/vereign_ca.key" ) func TestSetAndGetKeys(t *testing.T) { - dataStorageClient := utils.CreateClientFromUuidAndSession("viam-system", "viam-session", dataStorageGrpcAddress, certFile) + dataStorageClient := utils.CreateClientFromUuidAndSession("viam-system", "viam-session", dataStorageGrpcAddress, certFilePath) keyStorageAuth := &authentication.Authentication{ Uuid: "some-uuid", @@ -49,7 +51,7 @@ func TestSetAndGetKeys(t *testing.T) { _, _, _ = dataStorageClient.RenewSession(keyStorageAuth.Uuid, keyStorageAuth.Session) keyStorageClient := &ksclient.KeyStorageClientImpl{} - keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFile) + keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFilePath) defer keyStorageClient.CloseClient() uuid, statusList, _ := keyStorageClient.DoReserveKeyUUID() @@ -83,6 +85,15 @@ func TestSetAndGetKeys(t *testing.T) { []byte{0, 1, 2}, privateKeyResult.Content) } + // Test setting the same key twice + statusList, _ = keyStorageClient.DoSetKey(uuid, ksapi.KeyType_PRIVATE, privateKey) + for _, status := range statusList { + if status.StatusType != ksapi.StatusType_ERROR { + t.Errorf("DoSetKey, expected error, but got success") + return + } + } + publicKey := &ksapi.Key{ Content: []byte{3, 4, 2}, } @@ -104,9 +115,34 @@ func TestSetAndGetKeys(t *testing.T) { t.Errorf("DoGetKey, incorrect publicKeyResult.Content, expected: %v, but was: %v", []byte{3, 4, 2}, publicKeyResult.Content) } + + statusList, _ = keyStorageClient.DoRevoke(uuid) + for _, status := range statusList { + if status.StatusType == ksapi.StatusType_ERROR { + t.Errorf("DoRevoke, returned error: %s.", status.Code+":"+status.Description) + } + } + revokedPrivateKeyResult, 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) + } + } + if revokedPrivateKeyResult.Revoked == false { + t.Errorf("DoRevoke, key was not revoked") + } + revokedPublicKeyResult, 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) + } + } + if revokedPublicKeyResult.Revoked == false { + t.Errorf("DoRevoke, key was not revoked") + } } func TestGenerateKeyPairAndCertificate(t *testing.T) { - dataStorageClient := utils.CreateClientFromUuidAndSession("viam-system", "viam-session", dataStorageGrpcAddress, certFile) + dataStorageClient := utils.CreateClientFromUuidAndSession("viam-system", "viam-session", dataStorageGrpcAddress, certFilePath) keyStorageAuth := &authentication.Authentication{ Uuid: "some-uuid", @@ -116,10 +152,10 @@ func TestGenerateKeyPairAndCertificate(t *testing.T) { _, _, _ = dataStorageClient.RenewSession(keyStorageAuth.Uuid, keyStorageAuth.Session) keyStorageClient := &ksclient.KeyStorageClientImpl{} - keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFile) + keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFilePath) defer keyStorageClient.CloseClient() - uuid, statusList, _ := keyStorageClient.DoGenerateKeyPair(256) + uuid, statusList, _ := keyStorageClient.DoGenerateKeyPair(2048) for _, status := range statusList { if status.StatusType == ksapi.StatusType_ERROR { t.Errorf("DoGenerateKeyPair, returned error: %s.", status.Code+":"+status.Description) @@ -191,15 +227,15 @@ func TestGenerateKeyPairAndCertificate(t *testing.T) { t.Errorf("DoGetKey, returned error: %s.", status.Code+":"+status.Description) } } - if certificate.Content == nil { - t.Errorf("DoGetKey, certificate.Content is nil") + if certificate == nil || certificate.Content == nil { + t.Errorf("DoGetKey, certificate is nil") } } func TestMain(m *testing.M) { // fire the gRPC server in a goroutine go func() { - err := dataStorageServer.StartGRPCServer(dataStorageGrpcAddress, certFile, keyFile) + err := dataStorageServer.StartGRPCServer(dataStorageGrpcAddress, certFilePath, privateKeyFilePath) if err != nil { log.Fatalf("failed to start gRPC server: %s", err) } @@ -210,7 +246,8 @@ func TestMain(m *testing.M) { // fire the gRPC server in a goroutine go func() { - err := StartGRPCServer(keyStorageGrpcAddress, certFile, keyFile, dataStorageGrpcAddress) + err := StartGRPCServer(keyStorageGrpcAddress, certFilePath, privateKeyFilePath, + vereignCertFilePath, vereignPrivateKeyFilePath, dataStorageGrpcAddress) if err != nil { log.Fatalf("failed to start gRPC server: %s", err) }