| package libtrust |
| |
| import ( |
| "crypto" |
| "crypto/ecdsa" |
| "crypto/rsa" |
| "crypto/x509" |
| "encoding/json" |
| "encoding/pem" |
| "errors" |
| "fmt" |
| "io" |
| ) |
| |
| // PublicKey is a generic interface for a Public Key. |
| type PublicKey interface { |
| // KeyType returns the key type for this key. For elliptic curve keys, |
| // this value should be "EC". For RSA keys, this value should be "RSA". |
| KeyType() string |
| // KeyID returns a distinct identifier which is unique to this Public Key. |
| // The format generated by this library is a base32 encoding of a 240 bit |
| // hash of the public key data divided into 12 groups like so: |
| // ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP |
| KeyID() string |
| // Verify verifyies the signature of the data in the io.Reader using this |
| // Public Key. 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. |
| Verify(data io.Reader, alg string, signature []byte) error |
| // 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 |
| CryptoPublicKey() crypto.PublicKey |
| // These public keys can be serialized to the standard JSON encoding for |
| // JSON Web Keys. See section 6 of the IETF draft RFC for JOSE JSON Web |
| // Algorithms. |
| MarshalJSON() ([]byte, error) |
| // These keys can also be serialized to the standard PEM encoding. |
| PEMBlock() (*pem.Block, error) |
| // The string representation of a key is its key type and ID. |
| String() string |
| AddExtendedField(string, interface{}) |
| GetExtendedField(string) interface{} |
| } |
| |
| // PrivateKey is a generic interface for a Private Key. |
| type PrivateKey interface { |
| // A PrivateKey contains all fields and methods of a PublicKey of the |
| // same type. The MarshalJSON method also outputs the private key as a |
| // JSON Web Key, and the PEMBlock method outputs the private key as a |
| // PEM block. |
| PublicKey |
| // PublicKey returns the PublicKey associated with this PrivateKey. |
| PublicKey() PublicKey |
| // Sign signs the data read from the io.Reader using a signature algorithm |
| // supported by the 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 identifier of the algorithm used. |
| Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) |
| // 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 |
| CryptoPrivateKey() crypto.PrivateKey |
| } |
| |
| // FromCryptoPublicKey returns a libtrust PublicKey representation of the given |
| // *ecdsa.PublicKey or *rsa.PublicKey. Returns a non-nil error when the given |
| // key is of an unsupported type. |
| func FromCryptoPublicKey(cryptoPublicKey crypto.PublicKey) (PublicKey, error) { |
| switch cryptoPublicKey := cryptoPublicKey.(type) { |
| case *ecdsa.PublicKey: |
| return fromECPublicKey(cryptoPublicKey) |
| case *rsa.PublicKey: |
| return fromRSAPublicKey(cryptoPublicKey), nil |
| default: |
| return nil, fmt.Errorf("public key type %T is not supported", cryptoPublicKey) |
| } |
| } |
| |
| // FromCryptoPrivateKey returns a libtrust PrivateKey representation of the given |
| // *ecdsa.PrivateKey or *rsa.PrivateKey. Returns a non-nil error when the given |
| // key is of an unsupported type. |
| func FromCryptoPrivateKey(cryptoPrivateKey crypto.PrivateKey) (PrivateKey, error) { |
| switch cryptoPrivateKey := cryptoPrivateKey.(type) { |
| case *ecdsa.PrivateKey: |
| return fromECPrivateKey(cryptoPrivateKey) |
| case *rsa.PrivateKey: |
| return fromRSAPrivateKey(cryptoPrivateKey), nil |
| default: |
| return nil, fmt.Errorf("private key type %T is not supported", cryptoPrivateKey) |
| } |
| } |
| |
| // UnmarshalPublicKeyPEM parses the PEM encoded data and returns a libtrust |
| // PublicKey or an error if there is a problem with the encoding. |
| func UnmarshalPublicKeyPEM(data []byte) (PublicKey, error) { |
| pemBlock, _ := pem.Decode(data) |
| if pemBlock == nil { |
| return nil, errors.New("unable to find PEM encoded data") |
| } else if pemBlock.Type != "PUBLIC KEY" { |
| return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type) |
| } |
| |
| return pubKeyFromPEMBlock(pemBlock) |
| } |
| |
| // UnmarshalPublicKeyPEMBundle parses the PEM encoded data as a bundle of |
| // PEM blocks appended one after the other and returns a slice of PublicKey |
| // objects that it finds. |
| func UnmarshalPublicKeyPEMBundle(data []byte) ([]PublicKey, error) { |
| pubKeys := []PublicKey{} |
| |
| for { |
| var pemBlock *pem.Block |
| pemBlock, data = pem.Decode(data) |
| if pemBlock == nil { |
| break |
| } else if pemBlock.Type != "PUBLIC KEY" { |
| return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type) |
| } |
| |
| pubKey, err := pubKeyFromPEMBlock(pemBlock) |
| if err != nil { |
| return nil, err |
| } |
| |
| pubKeys = append(pubKeys, pubKey) |
| } |
| |
| return pubKeys, nil |
| } |
| |
| // UnmarshalPrivateKeyPEM parses the PEM encoded data and returns a libtrust |
| // PrivateKey or an error if there is a problem with the encoding. |
| func UnmarshalPrivateKeyPEM(data []byte) (PrivateKey, error) { |
| pemBlock, _ := pem.Decode(data) |
| if pemBlock == nil { |
| return nil, errors.New("unable to find PEM encoded data") |
| } |
| |
| var key PrivateKey |
| |
| switch { |
| case pemBlock.Type == "RSA PRIVATE KEY": |
| rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) |
| if err != nil { |
| return nil, fmt.Errorf("unable to decode RSA Private Key PEM data: %s", err) |
| } |
| key = fromRSAPrivateKey(rsaPrivateKey) |
| case pemBlock.Type == "EC PRIVATE KEY": |
| ecPrivateKey, err := x509.ParseECPrivateKey(pemBlock.Bytes) |
| if err != nil { |
| return nil, fmt.Errorf("unable to decode EC Private Key PEM data: %s", err) |
| } |
| key, err = fromECPrivateKey(ecPrivateKey) |
| if err != nil { |
| return nil, err |
| } |
| default: |
| return nil, fmt.Errorf("unable to get PrivateKey from PEM type: %s", pemBlock.Type) |
| } |
| |
| addPEMHeadersToKey(pemBlock, key.PublicKey()) |
| |
| return key, nil |
| } |
| |
| // UnmarshalPublicKeyJWK unmarshals the given JSON Web Key into a generic |
| // Public Key to be used with libtrust. |
| func UnmarshalPublicKeyJWK(data []byte) (PublicKey, error) { |
| jwk := make(map[string]interface{}) |
| |
| err := json.Unmarshal(data, &jwk) |
| if err != nil { |
| return nil, fmt.Errorf( |
| "decoding JWK Public Key JSON data: %s\n", err, |
| ) |
| } |
| |
| // Get the Key Type value. |
| kty, err := stringFromMap(jwk, "kty") |
| if err != nil { |
| return nil, fmt.Errorf("JWK Public Key type: %s", err) |
| } |
| |
| switch { |
| case kty == "EC": |
| // Call out to unmarshal EC public key. |
| return ecPublicKeyFromMap(jwk) |
| case kty == "RSA": |
| // Call out to unmarshal RSA public key. |
| return rsaPublicKeyFromMap(jwk) |
| default: |
| return nil, fmt.Errorf( |
| "JWK Public Key type not supported: %q\n", kty, |
| ) |
| } |
| } |
| |
| // UnmarshalPublicKeyJWKSet parses the JSON encoded data as a JSON Web Key Set |
| // and returns a slice of Public Key objects. |
| func UnmarshalPublicKeyJWKSet(data []byte) ([]PublicKey, error) { |
| rawKeys, err := loadJSONKeySetRaw(data) |
| if err != nil { |
| return nil, err |
| } |
| |
| pubKeys := make([]PublicKey, 0, len(rawKeys)) |
| |
| for _, rawKey := range rawKeys { |
| pubKey, err := UnmarshalPublicKeyJWK(rawKey) |
| if err != nil { |
| return nil, err |
| } |
| pubKeys = append(pubKeys, pubKey) |
| } |
| |
| return pubKeys, nil |
| } |
| |
| // UnmarshalPrivateKeyJWK unmarshals the given JSON Web Key into a generic |
| // Private Key to be used with libtrust. |
| func UnmarshalPrivateKeyJWK(data []byte) (PrivateKey, error) { |
| jwk := make(map[string]interface{}) |
| |
| err := json.Unmarshal(data, &jwk) |
| if err != nil { |
| return nil, fmt.Errorf( |
| "decoding JWK Private Key JSON data: %s\n", err, |
| ) |
| } |
| |
| // Get the Key Type value. |
| kty, err := stringFromMap(jwk, "kty") |
| if err != nil { |
| return nil, fmt.Errorf("JWK Private Key type: %s", err) |
| } |
| |
| switch { |
| case kty == "EC": |
| // Call out to unmarshal EC private key. |
| return ecPrivateKeyFromMap(jwk) |
| case kty == "RSA": |
| // Call out to unmarshal RSA private key. |
| return rsaPrivateKeyFromMap(jwk) |
| default: |
| return nil, fmt.Errorf( |
| "JWK Private Key type not supported: %q\n", kty, |
| ) |
| } |
| } |