mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) HashiCorp, Inc.
 | 
						|
// SPDX-License-Identifier: MPL-2.0
 | 
						|
 | 
						|
package keysutil
 | 
						|
 | 
						|
import (
 | 
						|
	"crypto/x509"
 | 
						|
	"crypto/x509/pkix"
 | 
						|
	"encoding/asn1"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"golang.org/x/crypto/ed25519"
 | 
						|
)
 | 
						|
 | 
						|
// pkcs8 reflects an ASN.1, PKCS #8 PrivateKey. See
 | 
						|
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
 | 
						|
// and RFC 5208.
 | 
						|
//
 | 
						|
// Copied from Go: https://github.com/golang/go/blob/master/src/crypto/x509/pkcs8.go#L17-L80
 | 
						|
type pkcs8 struct {
 | 
						|
	Version    int
 | 
						|
	Algo       pkix.AlgorithmIdentifier
 | 
						|
	PrivateKey []byte
 | 
						|
	// optional attributes omitted.
 | 
						|
}
 | 
						|
 | 
						|
// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
 | 
						|
// References:
 | 
						|
//
 | 
						|
//	RFC 5915
 | 
						|
//	SEC1 - http://www.secg.org/sec1-v2.pdf
 | 
						|
//
 | 
						|
// Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
 | 
						|
// most cases it is not.
 | 
						|
//
 | 
						|
// Copied from Go: 	https://github.com/golang/go/blob/master/src/crypto/x509/sec1.go#L18-L31
 | 
						|
type ecPrivateKey struct {
 | 
						|
	Version       int
 | 
						|
	PrivateKey    []byte
 | 
						|
	NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
 | 
						|
 | 
						|
	// Because the PKCS8/RFC 5915 encoding of the Ed25519 key uses the
 | 
						|
	// RFC 8032 Ed25519 seed format, we can ignore the public key parameter
 | 
						|
	// and infer it later.
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	// See crypto/x509/x509.go in the Go toolchain source distribution.
 | 
						|
	oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
 | 
						|
 | 
						|
	// NSS encodes Ed25519 private keys with the OID 1.3.6.1.4.1.11591.15.1
 | 
						|
	// from https://tools.ietf.org/html/draft-josefsson-pkix-newcurves-01.
 | 
						|
	// See https://github.com/nss-dev/nss/blob/NSS_3_79_BRANCH/lib/util/secoid.c#L600-L603.
 | 
						|
	oidNSSPKIXEd25519 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11591, 15, 1}
 | 
						|
 | 
						|
	// Other implementations may use the OID 1.3.101.110 from
 | 
						|
	// https://datatracker.ietf.org/doc/html/rfc8410.
 | 
						|
	oidRFC8410Ed25519 = asn1.ObjectIdentifier{1, 3, 101, 110}
 | 
						|
 | 
						|
	// See crypto/x509/x509.go in the Go toolchain source distribution.
 | 
						|
	oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
 | 
						|
)
 | 
						|
 | 
						|
func isEd25519OID(oid asn1.ObjectIdentifier) bool {
 | 
						|
	return oidNSSPKIXEd25519.Equal(oid) || oidRFC8410Ed25519.Equal(oid)
 | 
						|
}
 | 
						|
 | 
						|
// ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form.
 | 
						|
//
 | 
						|
// It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, or a ed25519.PrivateKey.
 | 
						|
// More types might be supported in the future.
 | 
						|
//
 | 
						|
// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
 | 
						|
func ParsePKCS8Ed25519PrivateKey(der []byte) (key interface{}, err error) {
 | 
						|
	var privKey pkcs8
 | 
						|
	var ed25519Key ecPrivateKey
 | 
						|
 | 
						|
	var checkedOID bool
 | 
						|
 | 
						|
	// If this err is nil, we assume we directly have a ECPrivateKey structure
 | 
						|
	// with explicit OID; ignore this error for now and return the latter err
 | 
						|
	// instead if neither parse correctly.
 | 
						|
	if _, err := asn1.Unmarshal(der, &privKey); err == nil {
 | 
						|
		switch {
 | 
						|
		case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
 | 
						|
			bytes := privKey.Algo.Parameters.FullBytes
 | 
						|
			namedCurveOID := new(asn1.ObjectIdentifier)
 | 
						|
			if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
 | 
						|
				namedCurveOID = nil
 | 
						|
			}
 | 
						|
 | 
						|
			if namedCurveOID == nil || !isEd25519OID(*namedCurveOID) {
 | 
						|
				return nil, errors.New("keysutil: failed to parse private key (invalid, non-ed25519 curve parameter OID)")
 | 
						|
			}
 | 
						|
 | 
						|
			der = privKey.PrivateKey
 | 
						|
			checkedOID = true
 | 
						|
		default:
 | 
						|
			// The Go standard library already parses RFC 8410 keys; the
 | 
						|
			// inclusion of the OID here is in case it is used with the
 | 
						|
			// regular ECDSA PrivateKey structure, rather than the struct
 | 
						|
			// recognized by the Go standard library.
 | 
						|
			return nil, errors.New("keysutil: failed to parse key as ed25519 private key")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = asn1.Unmarshal(der, &ed25519Key)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("keysutil: failed to parse private key (inner Ed25519 ECPrivateKey format was incorrect): %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if !checkedOID && !isEd25519OID(ed25519Key.NamedCurveOID) {
 | 
						|
		return nil, errors.New("keysutil: failed to parse private key (invalid, non-ed25519 curve parameter OID)")
 | 
						|
	}
 | 
						|
 | 
						|
	if len(ed25519Key.PrivateKey) != 32 {
 | 
						|
		return nil, fmt.Errorf("keysutil: failed to parse private key as ed25519 private key: got %v bytes but expected %v byte RFC 8032 seed", len(ed25519Key.PrivateKey), ed25519.SeedSize)
 | 
						|
	}
 | 
						|
 | 
						|
	return ed25519.NewKeyFromSeed(ed25519Key.PrivateKey), nil
 | 
						|
}
 | 
						|
 | 
						|
// ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form.
 | 
						|
//
 | 
						|
// This helper only supports RSA/PSS keys (with OID 1.2.840.113549.1.1.10).
 | 
						|
//
 | 
						|
// It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, or a ed25519.PrivateKey.
 | 
						|
// More types might be supported in the future.
 | 
						|
//
 | 
						|
// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
 | 
						|
func ParsePKCS8RSAPSSPrivateKey(der []byte) (key interface{}, err error) {
 | 
						|
	var privKey pkcs8
 | 
						|
	if _, err := asn1.Unmarshal(der, &privKey); err == nil {
 | 
						|
		switch {
 | 
						|
		case privKey.Algo.Algorithm.Equal(oidSignatureRSAPSS):
 | 
						|
			// Fall through; there's no parameters here unlike ECDSA
 | 
						|
			// containers, so we can go to parsing the inner rsaPrivateKey
 | 
						|
			// object.
 | 
						|
		default:
 | 
						|
			return nil, errors.New("keysutil: failed to parse key as RSA PSS private key")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	key, err = x509.ParsePKCS1PrivateKey(privKey.PrivateKey)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("keysutil: failed to parse inner RSA PSS private key: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return key, nil
 | 
						|
}
 |