mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 10:37:56 +00:00 
			
		
		
		
	Refactor sign/issue response logic to be usable by CIEPS codebase (#22053)
- Extract out the sign/issue certificate (non-CA) response into a function that can be used by the CIEPS sign/issue API handlers.
This commit is contained in:
		| @@ -70,8 +70,61 @@ var ( | ||||
|  | ||||
| 	// OIDs for X.509 certificate extensions used below. | ||||
| 	oidExtensionSubjectAltName = []int{2, 5, 29, 17} | ||||
|  | ||||
| 	// Cloned from https://github.com/golang/go/blob/82c713feb05da594567631972082af2fcba0ee4f/src/crypto/x509/x509.go#L327-L379 | ||||
| 	oidSignatureMD2WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} | ||||
| 	oidSignatureMD5WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} | ||||
| 	oidSignatureSHA1WithRSA     = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} | ||||
| 	oidSignatureSHA256WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} | ||||
| 	oidSignatureSHA384WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} | ||||
| 	oidSignatureSHA512WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} | ||||
| 	oidSignatureRSAPSS          = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} | ||||
| 	oidSignatureDSAWithSHA1     = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} | ||||
| 	oidSignatureDSAWithSHA256   = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} | ||||
| 	oidSignatureECDSAWithSHA1   = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} | ||||
| 	oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} | ||||
| 	oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} | ||||
| 	oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} | ||||
| 	oidSignatureEd25519         = asn1.ObjectIdentifier{1, 3, 101, 112} | ||||
| 	oidISOSignatureSHA1WithRSA  = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} | ||||
|  | ||||
| 	signatureAlgorithmDetails = []struct { | ||||
| 		algo       x509.SignatureAlgorithm | ||||
| 		name       string | ||||
| 		oid        asn1.ObjectIdentifier | ||||
| 		pubKeyAlgo x509.PublicKeyAlgorithm | ||||
| 		hash       crypto.Hash | ||||
| 	}{ | ||||
| 		{x509.MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */}, | ||||
| 		{x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, x509.RSA, crypto.MD5}, | ||||
| 		{x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1}, | ||||
| 		{x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1}, | ||||
| 		{x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256}, | ||||
| 		{x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384}, | ||||
| 		{x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512}, | ||||
| 		{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256}, | ||||
| 		{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384}, | ||||
| 		{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512}, | ||||
| 		{x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1}, | ||||
| 		{x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256}, | ||||
| 		{x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1}, | ||||
| 		{x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256}, | ||||
| 		{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384}, | ||||
| 		{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512}, | ||||
| 		{x509.PureEd25519, "Ed25519", oidSignatureEd25519, x509.Ed25519, crypto.Hash(0) /* no pre-hashing */}, | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| func doesPublicKeyAlgoMatchSignatureAlgo(pubKey x509.PublicKeyAlgorithm, algo x509.SignatureAlgorithm) bool { | ||||
| 	for _, detail := range signatureAlgorithmDetails { | ||||
| 		if detail.algo == algo { | ||||
| 			return pubKey == detail.pubKeyAlgo | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func getFormat(data *framework.FieldData) string { | ||||
| 	format := data.Get("format").(string) | ||||
| 	switch format { | ||||
|   | ||||
| @@ -167,16 +167,6 @@ func buildPathSign(b *backend, pattern string, displayAttrs *framework.DisplayAt | ||||
| 								Description: `Time of expiration`, | ||||
| 								Required:    true, | ||||
| 							}, | ||||
| 							"private_key": { | ||||
| 								Type:        framework.TypeString, | ||||
| 								Description: `Private key`, | ||||
| 								Required:    false, | ||||
| 							}, | ||||
| 							"private_key_type": { | ||||
| 								Type:        framework.TypeString, | ||||
| 								Description: `Private key type`, | ||||
| 								Required:    false, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}}, | ||||
| 				}, | ||||
| @@ -260,16 +250,6 @@ func buildPathIssuerSignVerbatim(b *backend, pattern string, displayAttrs *frame | ||||
| 								Description: `Time of expiration`, | ||||
| 								Required:    true, | ||||
| 							}, | ||||
| 							"private_key": { | ||||
| 								Type:        framework.TypeString, | ||||
| 								Description: `Private key`, | ||||
| 								Required:    false, | ||||
| 							}, | ||||
| 							"private_key_type": { | ||||
| 								Type:        framework.TypeString, | ||||
| 								Description: `Private key type`, | ||||
| 								Required:    false, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}}, | ||||
| 				}, | ||||
| @@ -403,73 +383,23 @@ func (b *backend) pathIssueSignCert(ctx context.Context, req *logical.Request, d | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	signingCB, err := signingBundle.ToCertBundle() | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error converting raw signing bundle to cert bundle: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	cb, err := parsedBundle.ToCertBundle() | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error converting raw cert bundle to cert bundle: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	caChainGen := newCaChainOutput(parsedBundle, data) | ||||
|  | ||||
| 	respData := map[string]interface{}{ | ||||
| 		"expiration":    int64(parsedBundle.Certificate.NotAfter.Unix()), | ||||
| 		"serial_number": cb.SerialNumber, | ||||
| 	resp, err := signIssueApiResponse(data, parsedBundle, signingBundle, warnings) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	switch format { | ||||
| 	case "pem": | ||||
| 		respData["issuing_ca"] = signingCB.Certificate | ||||
| 		respData["certificate"] = cb.Certificate | ||||
| 		if caChainGen.containsChain() { | ||||
| 			respData["ca_chain"] = caChainGen.pemEncodedChain() | ||||
| 		} | ||||
| 		if !useCSR { | ||||
| 			respData["private_key"] = cb.PrivateKey | ||||
| 			respData["private_key_type"] = cb.PrivateKeyType | ||||
| 		} | ||||
|  | ||||
| 	case "pem_bundle": | ||||
| 		respData["issuing_ca"] = signingCB.Certificate | ||||
| 		respData["certificate"] = cb.ToPEMBundle() | ||||
| 		if caChainGen.containsChain() { | ||||
| 			respData["ca_chain"] = caChainGen.pemEncodedChain() | ||||
| 		} | ||||
| 		if !useCSR { | ||||
| 			respData["private_key"] = cb.PrivateKey | ||||
| 			respData["private_key_type"] = cb.PrivateKeyType | ||||
| 		} | ||||
|  | ||||
| 	case "der": | ||||
| 		respData["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) | ||||
| 		respData["issuing_ca"] = base64.StdEncoding.EncodeToString(signingBundle.CertificateBytes) | ||||
|  | ||||
| 		if caChainGen.containsChain() { | ||||
| 			respData["ca_chain"] = caChainGen.derEncodedChain() | ||||
| 		} | ||||
|  | ||||
| 		if !useCSR { | ||||
| 			respData["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes) | ||||
| 			respData["private_key_type"] = cb.PrivateKeyType | ||||
| 		} | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unsupported format: %s", format) | ||||
| 	} | ||||
|  | ||||
| 	var resp *logical.Response | ||||
| 	switch { | ||||
| 	case role.GenerateLease == nil: | ||||
| 		return nil, fmt.Errorf("generate lease in role is nil") | ||||
| 	case !*role.GenerateLease: | ||||
| 		// If lease generation is disabled do not populate `Secret` field in | ||||
| 		// the response | ||||
| 		resp = &logical.Response{ | ||||
| 			Data: respData, | ||||
| 		} | ||||
| 		// Use resp from above | ||||
| 	default: | ||||
| 		respData := resp.Data | ||||
| 		resp = b.Secret(SecretCertsType).Response( | ||||
| 			respData, | ||||
| 			map[string]interface{}{ | ||||
| @@ -478,13 +408,6 @@ func (b *backend) pathIssueSignCert(ctx context.Context, req *logical.Request, d | ||||
| 		resp.Secret.TTL = parsedBundle.Certificate.NotAfter.Sub(time.Now()) | ||||
| 	} | ||||
|  | ||||
| 	if data.Get("private_key_format").(string) == "pkcs8" { | ||||
| 		err = convertRespToPKCS8(resp) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !role.NoStore { | ||||
| 		key := "certs/" + normalizeSerial(cb.SerialNumber) | ||||
| 		certsCounted := b.certsCounted.Load() | ||||
| @@ -556,6 +479,83 @@ func (cac *caChainOutput) derEncodedChain() []string { | ||||
| 	return derCaChain | ||||
| } | ||||
|  | ||||
| func signIssueApiResponse(data *framework.FieldData, parsedBundle *certutil.ParsedCertBundle, signingBundle *certutil.CAInfoBundle, warnings []string) (*logical.Response, error) { | ||||
| 	cb, err := parsedBundle.ToCertBundle() | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error converting raw cert bundle to cert bundle: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	signingCB, err := signingBundle.ToCertBundle() | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error converting raw signing bundle to cert bundle: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	caChainGen := newCaChainOutput(parsedBundle, data) | ||||
| 	includeKey := parsedBundle.PrivateKey != nil | ||||
|  | ||||
| 	respData := map[string]interface{}{ | ||||
| 		"expiration":    parsedBundle.Certificate.NotAfter.Unix(), | ||||
| 		"serial_number": cb.SerialNumber, | ||||
| 	} | ||||
|  | ||||
| 	format := getFormat(data) | ||||
| 	switch format { | ||||
| 	case "pem": | ||||
| 		respData["issuing_ca"] = signingCB.Certificate | ||||
| 		respData["certificate"] = cb.Certificate | ||||
| 		if caChainGen.containsChain() { | ||||
| 			respData["ca_chain"] = caChainGen.pemEncodedChain() | ||||
| 		} | ||||
| 		if includeKey { | ||||
| 			respData["private_key"] = cb.PrivateKey | ||||
| 			respData["private_key_type"] = cb.PrivateKeyType | ||||
| 		} | ||||
|  | ||||
| 	case "pem_bundle": | ||||
| 		respData["issuing_ca"] = signingCB.Certificate | ||||
| 		respData["certificate"] = cb.ToPEMBundle() | ||||
| 		if caChainGen.containsChain() { | ||||
| 			respData["ca_chain"] = caChainGen.pemEncodedChain() | ||||
| 		} | ||||
| 		if includeKey { | ||||
| 			respData["private_key"] = cb.PrivateKey | ||||
| 			respData["private_key_type"] = cb.PrivateKeyType | ||||
| 		} | ||||
|  | ||||
| 	case "der": | ||||
| 		respData["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) | ||||
| 		respData["issuing_ca"] = base64.StdEncoding.EncodeToString(signingBundle.CertificateBytes) | ||||
|  | ||||
| 		if caChainGen.containsChain() { | ||||
| 			respData["ca_chain"] = caChainGen.derEncodedChain() | ||||
| 		} | ||||
|  | ||||
| 		if includeKey { | ||||
| 			respData["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes) | ||||
| 			respData["private_key_type"] = cb.PrivateKeyType | ||||
| 		} | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unsupported format: %s", format) | ||||
| 	} | ||||
|  | ||||
| 	resp := &logical.Response{ | ||||
| 		Data: respData, | ||||
| 	} | ||||
|  | ||||
| 	if includeKey { | ||||
| 		if keyFormat := data.Get("private_key_format"); keyFormat == "pkcs8" { | ||||
| 			err := convertRespToPKCS8(resp) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	resp = addWarnings(resp, warnings) | ||||
|  | ||||
| 	return resp, nil | ||||
| } | ||||
|  | ||||
| const pathIssueHelpSyn = ` | ||||
| Request a certificate using a certain role with the provided details. | ||||
| ` | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Steven Clark
					Steven Clark