Newer
Older
/*
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"
keyutils "code.vereign.com/code/key-storage-agent/utils"
"code.vereign.com/code/viam-apis/key-storage-agent/api"
"code.vereign.com/code/viam-apis/utils"
"golang.org/x/net/context"
)

Viktor Popov
committed
func (s *KeyStorageServerImpl) GenerateKeyPair(ctx context.Context,
in *api.GenerateKeyPairRequest) (*api.GenerateKeyPairResponse, error) {
auth := s.CreateAuthentication(ctx)
client := keyutils.CreateDataStorageClient(auth)
defer client.CloseClient()
generateKeyPairResponse := &api.GenerateKeyPairResponse{}
uuid, err := keyutils.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())
}
encryptedPrivateKeyBytes, privateKeyNonce, 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.PutData("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE), encryptedPrivateKey)
generateKeyPairResponse.StatusList = keyutils.HandlePutDataErrors(generateKeyPairResponse.StatusList, errors, err)
if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 {

Viktor Popov
committed
publicKey := &api.Key{Content: publicKeyBytes}
result, errors, err = client.PutData("keys", uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC), publicKey)
generateKeyPairResponse.StatusList = keyutils.HandlePutDataErrors(generateKeyPairResponse.StatusList, errors, err)

Viktor Popov
committed
}
//duplicate logic of ReserveKeyUUID
if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 {
emptyKey := &api.Key{Content: []byte{}}
result, errors, err = client.PutData("keys", uuid+"/"+api.KeyType.String(api.KeyType_CERTIFICATE), emptyKey)
generateKeyPairResponse.StatusList = keyutils.HandlePutDataErrors(generateKeyPairResponse.StatusList, errors, err)

Viktor Popov
committed
if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 {
encryptedAesKeyBytes, err := rsaEncryptWithServerKey(s.VereignCertPEM, aesKeyBytes, []byte("aeskeys"))
if err != nil {
generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
"500", api.StatusType_ERROR, err.Error())
return generateKeyPairResponse, nil
}

Viktor Popov
committed
encryptedAesKey := &api.Key{Content: encryptedAesKeyBytes}
result, errors, err = client.PutData("keys", uuid+"/"+api.KeyType.String(api.KeyType_AES), encryptedAesKey)
generateKeyPairResponse.StatusList = keyutils.HandlePutDataErrors(generateKeyPairResponse.StatusList, errors, err)

Viktor Popov
committed
if generateKeyPairResponse.StatusList == nil || len(generateKeyPairResponse.StatusList) == 0 {
encryptedPrivateKeyNonceBytes, err := rsaEncryptWithServerKey(s.VereignCertPEM, privateKeyNonce, []byte("nonce"))

Viktor Popov
committed
if err != nil {

Viktor Popov
committed
generateKeyPairResponse.StatusList = utils.AddStatus(generateKeyPairResponse.StatusList,
"500", api.StatusType_ERROR, err.Error())
return generateKeyPairResponse, nil
}
encryptedNonce := &api.Key{Content: encryptedPrivateKeyNonceBytes}
result, errors, err = client.PutData("keys", uuid+"/"+api.KeyType.String(api.KeyType_NONCE), encryptedNonce)
generateKeyPairResponse.StatusList = keyutils.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
pkcs8PrivateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, nil, err
}
privateKeyPemBlock := &pem.Block{
Bytes: pkcs8PrivateKeyBytes,
}
privateKeyBytes := pem.EncodeToMemory(privateKeyPemBlock)
pkixPublicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return nil, nil, err
}
Bytes: pkixPublicKeyBytes,
}
publicKeyBytes := pem.EncodeToMemory(publicKeyPemBlock)
return privateKeyBytes, publicKeyBytes, nil
}
func rsaEncryptWithServerKey(certPEM []byte, message []byte, label []byte) ([]byte, error) {
serverCertificate, err := keyutils.ReadCertificateFromPEM(certPEM)
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
}