123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- package libtrust
- import (
- "crypto"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/x509"
- "encoding/json"
- "encoding/pem"
- "errors"
- "fmt"
- "io"
- "math/big"
- )
- /*
- * EC DSA PUBLIC KEY
- */
- // ecPublicKey implements a libtrust.PublicKey using elliptic curve digital
- // signature algorithms.
- type ecPublicKey struct {
- *ecdsa.PublicKey
- curveName string
- signatureAlgorithm *signatureAlgorithm
- extended map[string]interface{}
- }
- func fromECPublicKey(cryptoPublicKey *ecdsa.PublicKey) (*ecPublicKey, error) {
- curve := cryptoPublicKey.Curve
- switch {
- case curve == elliptic.P256():
- return &ecPublicKey{cryptoPublicKey, "P-256", es256, map[string]interface{}{}}, nil
- case curve == elliptic.P384():
- return &ecPublicKey{cryptoPublicKey, "P-384", es384, map[string]interface{}{}}, nil
- case curve == elliptic.P521():
- return &ecPublicKey{cryptoPublicKey, "P-521", es512, map[string]interface{}{}}, nil
- default:
- return nil, errors.New("unsupported elliptic curve")
- }
- }
- // KeyType returns the key type for elliptic curve keys, i.e., "EC".
- func (k *ecPublicKey) KeyType() string {
- return "EC"
- }
- // CurveName returns the elliptic curve identifier.
- // Possible values are "P-256", "P-384", and "P-521".
- func (k *ecPublicKey) CurveName() string {
- return k.curveName
- }
- // KeyID returns a distinct identifier which is unique to this Public Key.
- func (k *ecPublicKey) KeyID() string {
- return keyIDFromCryptoKey(k)
- }
- func (k *ecPublicKey) String() string {
- return fmt.Sprintf("EC Public Key <%s>", k.KeyID())
- }
- // Verify verifyies the signature of the data in the io.Reader using this
- // PublicKey. The alg parameter should identify the digital signature
- // algorithm which was used to produce the signature and should be supported
- // by this public key. Returns a nil error if the signature is valid.
- func (k *ecPublicKey) Verify(data io.Reader, alg string, signature []byte) error {
- // For EC keys there is only one supported signature algorithm depending
- // on the curve parameters.
- if k.signatureAlgorithm.HeaderParam() != alg {
- return fmt.Errorf("unable to verify signature: EC Public Key with curve %q does not support signature algorithm %q", k.curveName, alg)
- }
- // signature is the concatenation of (r, s), base64Url encoded.
- sigLength := len(signature)
- expectedOctetLength := 2 * ((k.Params().BitSize + 7) >> 3)
- if sigLength != expectedOctetLength {
- return fmt.Errorf("signature length is %d octets long, should be %d", sigLength, expectedOctetLength)
- }
- rBytes, sBytes := signature[:sigLength/2], signature[sigLength/2:]
- r := new(big.Int).SetBytes(rBytes)
- s := new(big.Int).SetBytes(sBytes)
- hasher := k.signatureAlgorithm.HashID().New()
- _, err := io.Copy(hasher, data)
- if err != nil {
- return fmt.Errorf("error reading data to sign: %s", err)
- }
- hash := hasher.Sum(nil)
- if !ecdsa.Verify(k.PublicKey, hash, r, s) {
- return errors.New("invalid signature")
- }
- return nil
- }
- // CryptoPublicKey returns the internal object which can be used as a
- // crypto.PublicKey for use with other standard library operations. The type
- // is either *rsa.PublicKey or *ecdsa.PublicKey
- func (k *ecPublicKey) CryptoPublicKey() crypto.PublicKey {
- return k.PublicKey
- }
- func (k *ecPublicKey) toMap() map[string]interface{} {
- jwk := make(map[string]interface{})
- for k, v := range k.extended {
- jwk[k] = v
- }
- jwk["kty"] = k.KeyType()
- jwk["kid"] = k.KeyID()
- jwk["crv"] = k.CurveName()
- xBytes := k.X.Bytes()
- yBytes := k.Y.Bytes()
- octetLength := (k.Params().BitSize + 7) >> 3
- // MUST include leading zeros in the output so that x, y are each
- // *octetLength* bytes long.
- xBuf := make([]byte, octetLength-len(xBytes), octetLength)
- yBuf := make([]byte, octetLength-len(yBytes), octetLength)
- xBuf = append(xBuf, xBytes...)
- yBuf = append(yBuf, yBytes...)
- jwk["x"] = joseBase64UrlEncode(xBuf)
- jwk["y"] = joseBase64UrlEncode(yBuf)
- return jwk
- }
- // MarshalJSON serializes this Public Key using the JWK JSON serialization format for
- // elliptic curve keys.
- func (k *ecPublicKey) MarshalJSON() (data []byte, err error) {
- return json.Marshal(k.toMap())
- }
- // PEMBlock serializes this Public Key to DER-encoded PKIX format.
- func (k *ecPublicKey) PEMBlock() (*pem.Block, error) {
- derBytes, err := x509.MarshalPKIXPublicKey(k.PublicKey)
- if err != nil {
- return nil, fmt.Errorf("unable to serialize EC PublicKey to DER-encoded PKIX format: %s", err)
- }
- k.extended["kid"] = k.KeyID() // For display purposes.
- return createPemBlock("PUBLIC KEY", derBytes, k.extended)
- }
- func (k *ecPublicKey) AddExtendedField(field string, value interface{}) {
- k.extended[field] = value
- }
- func (k *ecPublicKey) GetExtendedField(field string) interface{} {
- v, ok := k.extended[field]
- if !ok {
- return nil
- }
- return v
- }
- func ecPublicKeyFromMap(jwk map[string]interface{}) (*ecPublicKey, error) {
- // JWK key type (kty) has already been determined to be "EC".
- // Need to extract 'crv', 'x', 'y', and 'kid' and check for
- // consistency.
- // Get the curve identifier value.
- crv, err := stringFromMap(jwk, "crv")
- if err != nil {
- return nil, fmt.Errorf("JWK EC Public Key curve identifier: %s", err)
- }
- var (
- curve elliptic.Curve
- sigAlg *signatureAlgorithm
- )
- switch {
- case crv == "P-256":
- curve = elliptic.P256()
- sigAlg = es256
- case crv == "P-384":
- curve = elliptic.P384()
- sigAlg = es384
- case crv == "P-521":
- curve = elliptic.P521()
- sigAlg = es512
- default:
- return nil, fmt.Errorf("JWK EC Public Key curve identifier not supported: %q\n", crv)
- }
- // Get the X and Y coordinates for the public key point.
- xB64Url, err := stringFromMap(jwk, "x")
- if err != nil {
- return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err)
- }
- x, err := parseECCoordinate(xB64Url, curve)
- if err != nil {
- return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err)
- }
- yB64Url, err := stringFromMap(jwk, "y")
- if err != nil {
- return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err)
- }
- y, err := parseECCoordinate(yB64Url, curve)
- if err != nil {
- return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err)
- }
- key := &ecPublicKey{
- PublicKey: &ecdsa.PublicKey{Curve: curve, X: x, Y: y},
- curveName: crv, signatureAlgorithm: sigAlg,
- }
- // Key ID is optional too, but if it exists, it should match the key.
- _, ok := jwk["kid"]
- if ok {
- kid, err := stringFromMap(jwk, "kid")
- if err != nil {
- return nil, fmt.Errorf("JWK EC Public Key ID: %s", err)
- }
- if kid != key.KeyID() {
- return nil, fmt.Errorf("JWK EC Public Key ID does not match: %s", kid)
- }
- }
- key.extended = jwk
- return key, nil
- }
- /*
- * EC DSA PRIVATE KEY
- */
- // ecPrivateKey implements a JWK Private Key using elliptic curve digital signature
- // algorithms.
- type ecPrivateKey struct {
- ecPublicKey
- *ecdsa.PrivateKey
- }
- func fromECPrivateKey(cryptoPrivateKey *ecdsa.PrivateKey) (*ecPrivateKey, error) {
- publicKey, err := fromECPublicKey(&cryptoPrivateKey.PublicKey)
- if err != nil {
- return nil, err
- }
- return &ecPrivateKey{*publicKey, cryptoPrivateKey}, nil
- }
- // PublicKey returns the Public Key data associated with this Private Key.
- func (k *ecPrivateKey) PublicKey() PublicKey {
- return &k.ecPublicKey
- }
- func (k *ecPrivateKey) String() string {
- return fmt.Sprintf("EC Private Key <%s>", k.KeyID())
- }
- // Sign signs the data read from the io.Reader using a signature algorithm supported
- // by the elliptic curve private key. If the specified hashing algorithm is
- // supported by this key, that hash function is used to generate the signature
- // otherwise the the default hashing algorithm for this key is used. Returns
- // the signature and the name of the JWK signature algorithm used, e.g.,
- // "ES256", "ES384", "ES512".
- func (k *ecPrivateKey) Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) {
- // Generate a signature of the data using the internal alg.
- // The given hashId is only a suggestion, and since EC keys only support
- // on signature/hash algorithm given the curve name, we disregard it for
- // the elliptic curve JWK signature implementation.
- hasher := k.signatureAlgorithm.HashID().New()
- _, err = io.Copy(hasher, data)
- if err != nil {
- return nil, "", fmt.Errorf("error reading data to sign: %s", err)
- }
- hash := hasher.Sum(nil)
- r, s, err := ecdsa.Sign(rand.Reader, k.PrivateKey, hash)
- if err != nil {
- return nil, "", fmt.Errorf("error producing signature: %s", err)
- }
- rBytes, sBytes := r.Bytes(), s.Bytes()
- octetLength := (k.ecPublicKey.Params().BitSize + 7) >> 3
- // MUST include leading zeros in the output
- rBuf := make([]byte, octetLength-len(rBytes), octetLength)
- sBuf := make([]byte, octetLength-len(sBytes), octetLength)
- rBuf = append(rBuf, rBytes...)
- sBuf = append(sBuf, sBytes...)
- signature = append(rBuf, sBuf...)
- alg = k.signatureAlgorithm.HeaderParam()
- return
- }
- // CryptoPrivateKey returns the internal object which can be used as a
- // crypto.PublicKey for use with other standard library operations. The type
- // is either *rsa.PublicKey or *ecdsa.PublicKey
- func (k *ecPrivateKey) CryptoPrivateKey() crypto.PrivateKey {
- return k.PrivateKey
- }
- func (k *ecPrivateKey) toMap() map[string]interface{} {
- jwk := k.ecPublicKey.toMap()
- dBytes := k.D.Bytes()
- // The length of this octet string MUST be ceiling(log-base-2(n)/8)
- // octets (where n is the order of the curve). This is because the private
- // key d must be in the interval [1, n-1] so the bitlength of d should be
- // no larger than the bitlength of n-1. The easiest way to find the octet
- // length is to take bitlength(n-1), add 7 to force a carry, and shift this
- // bit sequence right by 3, which is essentially dividing by 8 and adding
- // 1 if there is any remainder. Thus, the private key value d should be
- // output to (bitlength(n-1)+7)>>3 octets.
- n := k.ecPublicKey.Params().N
- octetLength := (new(big.Int).Sub(n, big.NewInt(1)).BitLen() + 7) >> 3
- // Create a buffer with the necessary zero-padding.
- dBuf := make([]byte, octetLength-len(dBytes), octetLength)
- dBuf = append(dBuf, dBytes...)
- jwk["d"] = joseBase64UrlEncode(dBuf)
- return jwk
- }
- // MarshalJSON serializes this Private Key using the JWK JSON serialization format for
- // elliptic curve keys.
- func (k *ecPrivateKey) MarshalJSON() (data []byte, err error) {
- return json.Marshal(k.toMap())
- }
- // PEMBlock serializes this Private Key to DER-encoded PKIX format.
- func (k *ecPrivateKey) PEMBlock() (*pem.Block, error) {
- derBytes, err := x509.MarshalECPrivateKey(k.PrivateKey)
- if err != nil {
- return nil, fmt.Errorf("unable to serialize EC PrivateKey to DER-encoded PKIX format: %s", err)
- }
- k.extended["keyID"] = k.KeyID() // For display purposes.
- return createPemBlock("EC PRIVATE KEY", derBytes, k.extended)
- }
- func ecPrivateKeyFromMap(jwk map[string]interface{}) (*ecPrivateKey, error) {
- dB64Url, err := stringFromMap(jwk, "d")
- if err != nil {
- return nil, fmt.Errorf("JWK EC Private Key: %s", err)
- }
- // JWK key type (kty) has already been determined to be "EC".
- // Need to extract the public key information, then extract the private
- // key value 'd'.
- publicKey, err := ecPublicKeyFromMap(jwk)
- if err != nil {
- return nil, err
- }
- d, err := parseECPrivateParam(dB64Url, publicKey.Curve)
- if err != nil {
- return nil, fmt.Errorf("JWK EC Private Key d-param: %s", err)
- }
- key := &ecPrivateKey{
- ecPublicKey: *publicKey,
- PrivateKey: &ecdsa.PrivateKey{
- PublicKey: *publicKey.PublicKey,
- D: d,
- },
- }
- return key, nil
- }
- /*
- * Key Generation Functions.
- */
- func generateECPrivateKey(curve elliptic.Curve) (k *ecPrivateKey, err error) {
- k = new(ecPrivateKey)
- k.PrivateKey, err = ecdsa.GenerateKey(curve, rand.Reader)
- if err != nil {
- return nil, err
- }
- k.ecPublicKey.PublicKey = &k.PrivateKey.PublicKey
- k.extended = make(map[string]interface{})
- return
- }
- // GenerateECP256PrivateKey generates a key pair using elliptic curve P-256.
- func GenerateECP256PrivateKey() (PrivateKey, error) {
- k, err := generateECPrivateKey(elliptic.P256())
- if err != nil {
- return nil, fmt.Errorf("error generating EC P-256 key: %s", err)
- }
- k.curveName = "P-256"
- k.signatureAlgorithm = es256
- return k, nil
- }
- // GenerateECP384PrivateKey generates a key pair using elliptic curve P-384.
- func GenerateECP384PrivateKey() (PrivateKey, error) {
- k, err := generateECPrivateKey(elliptic.P384())
- if err != nil {
- return nil, fmt.Errorf("error generating EC P-384 key: %s", err)
- }
- k.curveName = "P-384"
- k.signatureAlgorithm = es384
- return k, nil
- }
- // GenerateECP521PrivateKey generates aß key pair using elliptic curve P-521.
- func GenerateECP521PrivateKey() (PrivateKey, error) {
- k, err := generateECPrivateKey(elliptic.P521())
- if err != nil {
- return nil, fmt.Errorf("error generating EC P-521 key: %s", err)
- }
- k.curveName = "P-521"
- k.signatureAlgorithm = es512
- return k, nil
- }
|