/* 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 /* TODO remove this file 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{} publicKeyMessage, statusList := getKey(client, in.Uuid, api.KeyType_PUBLIC) if statusList != nil { generateCertificateResponse.StatusList = statusList return generateCertificateResponse, nil } certificateBytes, err := generateCertificate(publicKeyMessage.Content, s.VereignCertFilePath, s.VereignPrivateKeyFilePath, 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.PutData("keys", in.Uuid+"/"+api.KeyType.String(api.KeyType_CERTIFICATE), certificateMessage) 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(publicKeyBytes []byte, caCertFilePath string, caPrivateKeyFilePath string, certificateData *api.CertificateData) ([]byte, error) { publicKeyPemBlock, _ := pem.Decode(publicKeyBytes) publicKey, err := x509.ParsePKIXPublicKey(publicKeyPemBlock.Bytes) if err != nil { return nil, err } notBeforeTime := time.Unix(certificateData.NotBefore/1000, 0).UTC() notAfterTime := time.Unix(certificateData.NotAfter/1000, 0).UTC() max := new(big.Int) max.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(max, big.NewInt(1)) //Generate cryptographically strong pseudo-random between 0 - max sn, err := rand.Int(rand.Reader, max) if err != nil { return nil, err } template := x509.Certificate{ SerialNumber: sn, Subject: pkix.Name{ CommonName: certificateData.CommonName, }, NotBefore: notBeforeTime, NotAfter: notAfterTime, KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment | x509.KeyUsageCertSign | x509.KeyUsageCRLSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageEmailProtection, x509.ExtKeyUsageTimeStamping}, BasicConstraintsValid: true, IsCA: true, } if certificateData.Country != "" { template.Subject.Country = []string{certificateData.Country} } if certificateData.Locality != "" { template.Subject.Locality = []string{certificateData.Locality} } if certificateData.Province != "" { template.Subject.Province = []string{certificateData.Province} } if certificateData.Organization != "" { template.Subject.Organization = []string{certificateData.Organization} } if certificateData.OrganizationalUnit != "" { template.Subject.OrganizationalUnit = []string{certificateData.OrganizationalUnit} } if certificateData.Host != "" { template.DNSNames = []string{certificateData.Host} } if certificateData.Email != "" { template.EmailAddresses = []string{certificateData.Email} oidPKCS9EmailAddress := asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1} template.Subject.ExtraNames = []pkix.AttributeTypeAndValue{ { Type: oidPKCS9EmailAddress, Value: certificateData.Email, }, } } caCertificate, err := readCertificateFromFile(caCertFilePath) if err != nil { return nil, err } caPrivateKey, err := readPrivateKeyFromFile(caPrivateKeyFilePath) if err != nil { return nil, err } certificateBytes, err := x509.CreateCertificate(rand.Reader, &template, caCertificate, publicKey, caPrivateKey) if err != nil { return nil, err } certificatePemBlock := &pem.Block{ Type: "CERTIFICATE", Bytes: certificateBytes, } certificatePemBytes := pem.EncodeToMemory(certificatePemBlock) return certificatePemBytes, 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 } */