David K. Bainbridge | 215e024 | 2017-09-05 23:18:24 -0700 | [diff] [blame] | 1 | package libtrust |
| 2 | |
| 3 | import ( |
| 4 | "crypto" |
| 5 | "crypto/ecdsa" |
| 6 | "crypto/rsa" |
| 7 | "crypto/x509" |
| 8 | "encoding/json" |
| 9 | "encoding/pem" |
| 10 | "errors" |
| 11 | "fmt" |
| 12 | "io" |
| 13 | ) |
| 14 | |
| 15 | // PublicKey is a generic interface for a Public Key. |
| 16 | type PublicKey interface { |
| 17 | // KeyType returns the key type for this key. For elliptic curve keys, |
| 18 | // this value should be "EC". For RSA keys, this value should be "RSA". |
| 19 | KeyType() string |
| 20 | // KeyID returns a distinct identifier which is unique to this Public Key. |
| 21 | // The format generated by this library is a base32 encoding of a 240 bit |
| 22 | // hash of the public key data divided into 12 groups like so: |
| 23 | // ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP |
| 24 | KeyID() string |
| 25 | // Verify verifyies the signature of the data in the io.Reader using this |
| 26 | // Public Key. The alg parameter should identify the digital signature |
| 27 | // algorithm which was used to produce the signature and should be |
| 28 | // supported by this public key. Returns a nil error if the signature |
| 29 | // is valid. |
| 30 | Verify(data io.Reader, alg string, signature []byte) error |
| 31 | // CryptoPublicKey returns the internal object which can be used as a |
| 32 | // crypto.PublicKey for use with other standard library operations. The type |
| 33 | // is either *rsa.PublicKey or *ecdsa.PublicKey |
| 34 | CryptoPublicKey() crypto.PublicKey |
| 35 | // These public keys can be serialized to the standard JSON encoding for |
| 36 | // JSON Web Keys. See section 6 of the IETF draft RFC for JOSE JSON Web |
| 37 | // Algorithms. |
| 38 | MarshalJSON() ([]byte, error) |
| 39 | // These keys can also be serialized to the standard PEM encoding. |
| 40 | PEMBlock() (*pem.Block, error) |
| 41 | // The string representation of a key is its key type and ID. |
| 42 | String() string |
| 43 | AddExtendedField(string, interface{}) |
| 44 | GetExtendedField(string) interface{} |
| 45 | } |
| 46 | |
| 47 | // PrivateKey is a generic interface for a Private Key. |
| 48 | type PrivateKey interface { |
| 49 | // A PrivateKey contains all fields and methods of a PublicKey of the |
| 50 | // same type. The MarshalJSON method also outputs the private key as a |
| 51 | // JSON Web Key, and the PEMBlock method outputs the private key as a |
| 52 | // PEM block. |
| 53 | PublicKey |
| 54 | // PublicKey returns the PublicKey associated with this PrivateKey. |
| 55 | PublicKey() PublicKey |
| 56 | // Sign signs the data read from the io.Reader using a signature algorithm |
| 57 | // supported by the private key. If the specified hashing algorithm is |
| 58 | // supported by this key, that hash function is used to generate the |
| 59 | // signature otherwise the the default hashing algorithm for this key is |
| 60 | // used. Returns the signature and identifier of the algorithm used. |
| 61 | Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) |
| 62 | // CryptoPrivateKey returns the internal object which can be used as a |
| 63 | // crypto.PublicKey for use with other standard library operations. The |
| 64 | // type is either *rsa.PublicKey or *ecdsa.PublicKey |
| 65 | CryptoPrivateKey() crypto.PrivateKey |
| 66 | } |
| 67 | |
| 68 | // FromCryptoPublicKey returns a libtrust PublicKey representation of the given |
| 69 | // *ecdsa.PublicKey or *rsa.PublicKey. Returns a non-nil error when the given |
| 70 | // key is of an unsupported type. |
| 71 | func FromCryptoPublicKey(cryptoPublicKey crypto.PublicKey) (PublicKey, error) { |
| 72 | switch cryptoPublicKey := cryptoPublicKey.(type) { |
| 73 | case *ecdsa.PublicKey: |
| 74 | return fromECPublicKey(cryptoPublicKey) |
| 75 | case *rsa.PublicKey: |
| 76 | return fromRSAPublicKey(cryptoPublicKey), nil |
| 77 | default: |
| 78 | return nil, fmt.Errorf("public key type %T is not supported", cryptoPublicKey) |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | // FromCryptoPrivateKey returns a libtrust PrivateKey representation of the given |
| 83 | // *ecdsa.PrivateKey or *rsa.PrivateKey. Returns a non-nil error when the given |
| 84 | // key is of an unsupported type. |
| 85 | func FromCryptoPrivateKey(cryptoPrivateKey crypto.PrivateKey) (PrivateKey, error) { |
| 86 | switch cryptoPrivateKey := cryptoPrivateKey.(type) { |
| 87 | case *ecdsa.PrivateKey: |
| 88 | return fromECPrivateKey(cryptoPrivateKey) |
| 89 | case *rsa.PrivateKey: |
| 90 | return fromRSAPrivateKey(cryptoPrivateKey), nil |
| 91 | default: |
| 92 | return nil, fmt.Errorf("private key type %T is not supported", cryptoPrivateKey) |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | // UnmarshalPublicKeyPEM parses the PEM encoded data and returns a libtrust |
| 97 | // PublicKey or an error if there is a problem with the encoding. |
| 98 | func UnmarshalPublicKeyPEM(data []byte) (PublicKey, error) { |
| 99 | pemBlock, _ := pem.Decode(data) |
| 100 | if pemBlock == nil { |
| 101 | return nil, errors.New("unable to find PEM encoded data") |
| 102 | } else if pemBlock.Type != "PUBLIC KEY" { |
| 103 | return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type) |
| 104 | } |
| 105 | |
| 106 | return pubKeyFromPEMBlock(pemBlock) |
| 107 | } |
| 108 | |
| 109 | // UnmarshalPublicKeyPEMBundle parses the PEM encoded data as a bundle of |
| 110 | // PEM blocks appended one after the other and returns a slice of PublicKey |
| 111 | // objects that it finds. |
| 112 | func UnmarshalPublicKeyPEMBundle(data []byte) ([]PublicKey, error) { |
| 113 | pubKeys := []PublicKey{} |
| 114 | |
| 115 | for { |
| 116 | var pemBlock *pem.Block |
| 117 | pemBlock, data = pem.Decode(data) |
| 118 | if pemBlock == nil { |
| 119 | break |
| 120 | } else if pemBlock.Type != "PUBLIC KEY" { |
| 121 | return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type) |
| 122 | } |
| 123 | |
| 124 | pubKey, err := pubKeyFromPEMBlock(pemBlock) |
| 125 | if err != nil { |
| 126 | return nil, err |
| 127 | } |
| 128 | |
| 129 | pubKeys = append(pubKeys, pubKey) |
| 130 | } |
| 131 | |
| 132 | return pubKeys, nil |
| 133 | } |
| 134 | |
| 135 | // UnmarshalPrivateKeyPEM parses the PEM encoded data and returns a libtrust |
| 136 | // PrivateKey or an error if there is a problem with the encoding. |
| 137 | func UnmarshalPrivateKeyPEM(data []byte) (PrivateKey, error) { |
| 138 | pemBlock, _ := pem.Decode(data) |
| 139 | if pemBlock == nil { |
| 140 | return nil, errors.New("unable to find PEM encoded data") |
| 141 | } |
| 142 | |
| 143 | var key PrivateKey |
| 144 | |
| 145 | switch { |
| 146 | case pemBlock.Type == "RSA PRIVATE KEY": |
| 147 | rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) |
| 148 | if err != nil { |
| 149 | return nil, fmt.Errorf("unable to decode RSA Private Key PEM data: %s", err) |
| 150 | } |
| 151 | key = fromRSAPrivateKey(rsaPrivateKey) |
| 152 | case pemBlock.Type == "EC PRIVATE KEY": |
| 153 | ecPrivateKey, err := x509.ParseECPrivateKey(pemBlock.Bytes) |
| 154 | if err != nil { |
| 155 | return nil, fmt.Errorf("unable to decode EC Private Key PEM data: %s", err) |
| 156 | } |
| 157 | key, err = fromECPrivateKey(ecPrivateKey) |
| 158 | if err != nil { |
| 159 | return nil, err |
| 160 | } |
| 161 | default: |
| 162 | return nil, fmt.Errorf("unable to get PrivateKey from PEM type: %s", pemBlock.Type) |
| 163 | } |
| 164 | |
| 165 | addPEMHeadersToKey(pemBlock, key.PublicKey()) |
| 166 | |
| 167 | return key, nil |
| 168 | } |
| 169 | |
| 170 | // UnmarshalPublicKeyJWK unmarshals the given JSON Web Key into a generic |
| 171 | // Public Key to be used with libtrust. |
| 172 | func UnmarshalPublicKeyJWK(data []byte) (PublicKey, error) { |
| 173 | jwk := make(map[string]interface{}) |
| 174 | |
| 175 | err := json.Unmarshal(data, &jwk) |
| 176 | if err != nil { |
| 177 | return nil, fmt.Errorf( |
| 178 | "decoding JWK Public Key JSON data: %s\n", err, |
| 179 | ) |
| 180 | } |
| 181 | |
| 182 | // Get the Key Type value. |
| 183 | kty, err := stringFromMap(jwk, "kty") |
| 184 | if err != nil { |
| 185 | return nil, fmt.Errorf("JWK Public Key type: %s", err) |
| 186 | } |
| 187 | |
| 188 | switch { |
| 189 | case kty == "EC": |
| 190 | // Call out to unmarshal EC public key. |
| 191 | return ecPublicKeyFromMap(jwk) |
| 192 | case kty == "RSA": |
| 193 | // Call out to unmarshal RSA public key. |
| 194 | return rsaPublicKeyFromMap(jwk) |
| 195 | default: |
| 196 | return nil, fmt.Errorf( |
| 197 | "JWK Public Key type not supported: %q\n", kty, |
| 198 | ) |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | // UnmarshalPublicKeyJWKSet parses the JSON encoded data as a JSON Web Key Set |
| 203 | // and returns a slice of Public Key objects. |
| 204 | func UnmarshalPublicKeyJWKSet(data []byte) ([]PublicKey, error) { |
| 205 | rawKeys, err := loadJSONKeySetRaw(data) |
| 206 | if err != nil { |
| 207 | return nil, err |
| 208 | } |
| 209 | |
| 210 | pubKeys := make([]PublicKey, 0, len(rawKeys)) |
| 211 | |
| 212 | for _, rawKey := range rawKeys { |
| 213 | pubKey, err := UnmarshalPublicKeyJWK(rawKey) |
| 214 | if err != nil { |
| 215 | return nil, err |
| 216 | } |
| 217 | pubKeys = append(pubKeys, pubKey) |
| 218 | } |
| 219 | |
| 220 | return pubKeys, nil |
| 221 | } |
| 222 | |
| 223 | // UnmarshalPrivateKeyJWK unmarshals the given JSON Web Key into a generic |
| 224 | // Private Key to be used with libtrust. |
| 225 | func UnmarshalPrivateKeyJWK(data []byte) (PrivateKey, error) { |
| 226 | jwk := make(map[string]interface{}) |
| 227 | |
| 228 | err := json.Unmarshal(data, &jwk) |
| 229 | if err != nil { |
| 230 | return nil, fmt.Errorf( |
| 231 | "decoding JWK Private Key JSON data: %s\n", err, |
| 232 | ) |
| 233 | } |
| 234 | |
| 235 | // Get the Key Type value. |
| 236 | kty, err := stringFromMap(jwk, "kty") |
| 237 | if err != nil { |
| 238 | return nil, fmt.Errorf("JWK Private Key type: %s", err) |
| 239 | } |
| 240 | |
| 241 | switch { |
| 242 | case kty == "EC": |
| 243 | // Call out to unmarshal EC private key. |
| 244 | return ecPrivateKeyFromMap(jwk) |
| 245 | case kty == "RSA": |
| 246 | // Call out to unmarshal RSA private key. |
| 247 | return rsaPrivateKeyFromMap(jwk) |
| 248 | default: |
| 249 | return nil, fmt.Errorf( |
| 250 | "JWK Private Key type not supported: %q\n", kty, |
| 251 | ) |
| 252 | } |
| 253 | } |