예제 #1
0
// extKeyUsage decodes/prints extended key usage from a certificate.
func extKeyUsage(sEku simpleExtKeyUsage) string {
	eku := x509.ExtKeyUsage(sEku)
	val, ok := extKeyUsageStrings[eku]
	if ok {
		return val
	}
	return fmt.Sprintf("unknown:%d", eku)
}
예제 #2
0
파일: app.go 프로젝트: shaheemirza/CAGo
// Base code to actually create and store a new certificate
// Return the id of the new certificate(or -1) and an error (or nil)
func (c App) createCertificate(id int, certificate models.FullCertificate) (*models.Certificate, error) {

	// Keep track of whether this is a self signed certificate
	var sign_cert *models.Certificate

	// Get the CA certificate that is signing this new cert
	var project *models.Project
	if id >= 0 {
		project = c.getProject(id)
		if project == nil {
			return nil, errors.New("Unable to retreive project")
		}
		cas := c.getProjectCAs(project)

		ca := c.Params.Values["certificate.SignedBy"][0]
		ca_val, _ := strconv.Atoi(ca)
		for _, c := range cas {
			if c.Id == ca_val {
				sign_cert = c
			}
		}
	}

	serialNumber := 1
	caCount := &models.CACount{}
	var CRLLocation []string
	if sign_cert != nil {
		// Another Cert is CA
		obj, err := c.Txn.Get(models.CACount{}, sign_cert.Id)
		if err != nil {
			return nil, errors.New("Error determining Serial Number")
		}
		caCount = obj.(*models.CACount)
		serialNumber = caCount.SerialNumber + 1
		caCount.SerialNumber = serialNumber
		_, err = c.Txn.Update(caCount)
		if err != nil {
			return nil, newError("Error saving ca count", err)
		}
		// Use the CRL of the cert that is signing it
		CRLLocation := []string{c.makeCRLLocation(caCount.Id)}
		if certificate.IsCA {
			// This certificate should now have it's own
			CRLLocation = append(CRLLocation, c.makeCRLLocation(caCount.Id))

		}
	} else {
		crlCount := c.getCRLCount()
		CRLLocation = []string{c.makeCRLLocation(crlCount + 1)}

	}

	// Set up ways Key can be used
	certificate.KeyUses = c.Params.Values["certificate.KeyUses"]
	certificate.ExtKeyUses = c.Params.Values["certificate.ExtKeyUses"]

	//Set up primary key uses
	keyUsage := 0
	for _, use := range certificate.KeyUses {
		v, _ := strconv.Atoi(use)
		keyUsage = keyUsage | v
	}
	// CAs need to be able to sign other certificates and Certificate Revocation Lists
	if certificate.IsCA {
		keyUsage = keyUsage | int(x509.KeyUsageCertSign) | int(x509.KeyUsageCRLSign)
	}

	// Set up extra key uses for certificate
	extKeyUsage := make([]x509.ExtKeyUsage, 0)
	for _, use := range certificate.ExtKeyUses {
		v, _ := strconv.Atoi(use)
		extKeyUsage = append(extKeyUsage, x509.ExtKeyUsage(v))
	}

	endTime, _ := time.Parse("2006-01-02", certificate.Expires)

	encrypted := false

	template := x509.Certificate{
		SerialNumber: new(big.Int).SetInt64(int64(serialNumber)),
		Subject: pkix.Name{
			Organization:       []string{certificate.Organization},
			OrganizationalUnit: []string{certificate.OrganizationUnit},
			Country:            []string{certificate.Country},
			Province:           []string{certificate.State},
			Locality:           []string{certificate.City},
			CommonName:         certificate.CommonName,
		},
		NotBefore:             time.Now(),
		NotAfter:              endTime,
		IsCA:                  certificate.IsCA,
		KeyUsage:              x509.KeyUsage(keyUsage),
		ExtKeyUsage:           extKeyUsage,
		BasicConstraintsValid: true,
		CRLDistributionPoints: CRLLocation,
	}

	enc := strings.Split(certificate.PrivateKeyType, " ")
	var privCert []byte
	var pubCert []byte
	var keyType models.KeyType
	var signKey interface{}
	var parent *x509.Certificate

	// Create RSA Cert
	if strings.HasPrefix(enc[0], "RSA") {
		keyType = models.RSA
		size, err := strconv.Atoi(enc[1])
		if err != nil {
			return nil, newError("Failed to generate private key", err)
		}
		priv, err := rsa.GenerateKey(rand.Reader, size)

		if err != nil {
			return nil, newError("Failed to generate private key", err)
		}
		if sign_cert == nil {
			signKey = priv
			parent = &template
		} else {

			// Getting signed by CA, get CA private key bytes
			var ca_bytes []byte
			ca_block, _ := pem.Decode(sign_cert.PrivateKey)
			if ca_block == nil {
				return nil, newError("Unable to decode CA privatekey", nil)
			}
			ca_bytes = ca_block.Bytes
			if x509.IsEncryptedPEMBlock(ca_block) {
				if len(certificate.CAEncryptionKey) == 0 {
					return nil, errors.New("Unable to unlock CA key")
				} else {
					// CA is encrypted so decrypt it
					ca_bytes, err = x509.DecryptPEMBlock(ca_block, []byte(certificate.CAEncryptionKey))
					if err != nil {
						return nil, errors.New("Unable to decrypt CA key")
					}
				}
			}

			// Obtain the key for the CA for signing
			if sign_cert.KeyType == models.RSA {
				signKey, err = x509.ParsePKCS1PrivateKey(ca_bytes)
				if err != nil {
					return nil, newError("Error parsing certificate", err)
				}

			} else {
				signKey, err = x509.ParseECPrivateKey(ca_bytes)
				if err != nil {
					return nil, newError("Error parsing certificate", err)
				}
			}

			// We need the public certificate of the CA as well
			block, _ := pem.Decode(sign_cert.PEM)
			if block == nil {
				return nil, newError("Unable to decode CA cert", nil)
			}
			parent, err = x509.ParseCertificate(block.Bytes)
			if err != nil {
				return nil, newError("Failed to generate private key:", err)
			}

		}
		pub := priv.PublicKey
		marshalledKey := x509.MarshalPKCS1PrivateKey(priv)
		derBytes, err := x509.CreateCertificate(rand.Reader, &template, parent, &pub, signKey)
		if err != nil {
			return nil, newError("Failed to create certificate \n", err)
		}
		// Convert certificate to PEM to be stored in DB
		pubCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
		pemKeyBlock := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: marshalledKey}
		// Encrypt the private key if an encryption key was provided
		if len(certificate.EncryptionKey) > 0 {
			pemKeyBlock, err = x509.EncryptPEMBlock(rand.Reader, pemKeyBlock.Type, pemKeyBlock.Bytes, []byte(certificate.EncryptionKey), x509.PEMCipherAES256)
			if err != nil {
				return nil, newError("Failed to encrypt key", err)
			}
			encrypted = true
		}
		privCert = pem.EncodeToMemory(pemKeyBlock)

	} else { // Create ECDSA Cert

		keyType = models.ECDSA
		var curve elliptic.Curve
		// Select the Elliptic curve to use
		switch enc[1] {
		case "224":
			curve = elliptic.P224()

		case "256":
			curve = elliptic.P256()

		case "384":
			curve = elliptic.P384()

		case "521":
			curve = elliptic.P521()
		}
		priv, err := ecdsa.GenerateKey(curve, rand.Reader)
		pub := priv.PublicKey
		if err != nil {
			return nil, newError("Failed to generate private key", err)
		}

		if sign_cert == nil {
			signKey = priv
			parent = &template
		} else {

			// Getting signed by CA, get CA private key bytes
			var ca_bytes []byte
			ca_block, _ := pem.Decode(sign_cert.PrivateKey)
			if ca_block == nil {
				return nil, newError("Unable to decode CA privatekey", nil)
			}
			ca_bytes = ca_block.Bytes
			if x509.IsEncryptedPEMBlock(ca_block) {
				if len(certificate.CAEncryptionKey) == 0 {
					return nil, errors.New("Unable to unlock CA key")
				} else {
					// CA is encrypted so decrypt it
					ca_bytes, err = x509.DecryptPEMBlock(ca_block, []byte(certificate.CAEncryptionKey))
					if err != nil {
						return nil, errors.New("Unable to decrypt CA key")
					}
				}
			}

			// Obtain the key for the CA for signing
			if sign_cert.KeyType == models.RSA {
				signKey, err = x509.ParsePKCS1PrivateKey(ca_bytes)
				if err != nil {
					return nil, newError("Error parsing certificate", err)
				}

			} else {
				signKey, err = x509.ParseECPrivateKey(ca_bytes)
				if err != nil {
					return nil, newError("Error parsing certificate", err)
				}
			}

			// We need the public certificate of the CA as well
			block, _ := pem.Decode(sign_cert.PEM)
			if block == nil {
				return nil, newError("Unable to decode CA cert", nil)
			}
			parent, err = x509.ParseCertificate(block.Bytes)
			if err != nil {
				return nil, newError("Error parsing certificate", err)
			}

		}

		// All the parts to make a certificate are available
		// Create an x509 certificate
		derBytes, err := x509.CreateCertificate(rand.Reader, &template, parent, &pub, signKey)
		if err != nil {
			return nil, newError("Failed to create certificate", err)
		}

		// Convert certificate to PEM to be stored in DB
		pubCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})

		//marshalledKey, err := MarshalECPrivateKey(priv)
		marshalledKey, err := x509.MarshalECPrivateKey(priv) // To be used for go 1.2 (added to default x509 lib)
		if err != nil {
			return nil, newError("Failed Marshal EC Private Key", err)
		}

		pemKeyBlock := &pem.Block{Type: "EC PRIVATE KEY", Bytes: marshalledKey}
		if len(certificate.EncryptionKey) > 0 {
			pemKeyBlock, err = x509.EncryptPEMBlock(rand.Reader, pemKeyBlock.Type, pemKeyBlock.Bytes, []byte(certificate.EncryptionKey), x509.PEMCipherAES256)
			if err != nil {
				return nil, newError("Failed to encrypt key", err)
			}
			encrypted = true
		}
		privCert = pem.EncodeToMemory(pemKeyBlock)
	}

	// Create Certificate model for certificate table
	cert := models.Certificate{PEM: pubCert, PrivateKey: privCert, CommonName: certificate.CommonName, CA: certificate.IsCA, Project: project, KeyType: keyType, Encrypted: encrypted, SerialNumber: serialNumber}

	// Save the certificate in the database
	err := c.Txn.Insert(&cert)
	if err != nil {
		return nil, newError("Error saving certificate", err)
	}

	if sign_cert == nil {
		// Cert is self signed
		caCount.SerialNumber = serialNumber
		caCount.Certificate = &cert

		err := c.Txn.Insert(caCount)
		if err != nil {
			return nil, newError("Error saving ca count", err)
		}
	}

	return &cert, nil
}