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/elliptic" |
| 7 | "crypto/rand" |
| 8 | "crypto/x509" |
| 9 | "encoding/json" |
| 10 | "encoding/pem" |
| 11 | "errors" |
| 12 | "fmt" |
| 13 | "io" |
| 14 | "math/big" |
| 15 | ) |
| 16 | |
| 17 | /* |
| 18 | * EC DSA PUBLIC KEY |
| 19 | */ |
| 20 | |
| 21 | // ecPublicKey implements a libtrust.PublicKey using elliptic curve digital |
| 22 | // signature algorithms. |
| 23 | type ecPublicKey struct { |
| 24 | *ecdsa.PublicKey |
| 25 | curveName string |
| 26 | signatureAlgorithm *signatureAlgorithm |
| 27 | extended map[string]interface{} |
| 28 | } |
| 29 | |
| 30 | func fromECPublicKey(cryptoPublicKey *ecdsa.PublicKey) (*ecPublicKey, error) { |
| 31 | curve := cryptoPublicKey.Curve |
| 32 | |
| 33 | switch { |
| 34 | case curve == elliptic.P256(): |
| 35 | return &ecPublicKey{cryptoPublicKey, "P-256", es256, map[string]interface{}{}}, nil |
| 36 | case curve == elliptic.P384(): |
| 37 | return &ecPublicKey{cryptoPublicKey, "P-384", es384, map[string]interface{}{}}, nil |
| 38 | case curve == elliptic.P521(): |
| 39 | return &ecPublicKey{cryptoPublicKey, "P-521", es512, map[string]interface{}{}}, nil |
| 40 | default: |
| 41 | return nil, errors.New("unsupported elliptic curve") |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | // KeyType returns the key type for elliptic curve keys, i.e., "EC". |
| 46 | func (k *ecPublicKey) KeyType() string { |
| 47 | return "EC" |
| 48 | } |
| 49 | |
| 50 | // CurveName returns the elliptic curve identifier. |
| 51 | // Possible values are "P-256", "P-384", and "P-521". |
| 52 | func (k *ecPublicKey) CurveName() string { |
| 53 | return k.curveName |
| 54 | } |
| 55 | |
| 56 | // KeyID returns a distinct identifier which is unique to this Public Key. |
| 57 | func (k *ecPublicKey) KeyID() string { |
| 58 | return keyIDFromCryptoKey(k) |
| 59 | } |
| 60 | |
| 61 | func (k *ecPublicKey) String() string { |
| 62 | return fmt.Sprintf("EC Public Key <%s>", k.KeyID()) |
| 63 | } |
| 64 | |
| 65 | // Verify verifyies the signature of the data in the io.Reader using this |
| 66 | // PublicKey. The alg parameter should identify the digital signature |
| 67 | // algorithm which was used to produce the signature and should be supported |
| 68 | // by this public key. Returns a nil error if the signature is valid. |
| 69 | func (k *ecPublicKey) Verify(data io.Reader, alg string, signature []byte) error { |
| 70 | // For EC keys there is only one supported signature algorithm depending |
| 71 | // on the curve parameters. |
| 72 | if k.signatureAlgorithm.HeaderParam() != alg { |
| 73 | return fmt.Errorf("unable to verify signature: EC Public Key with curve %q does not support signature algorithm %q", k.curveName, alg) |
| 74 | } |
| 75 | |
| 76 | // signature is the concatenation of (r, s), base64Url encoded. |
| 77 | sigLength := len(signature) |
| 78 | expectedOctetLength := 2 * ((k.Params().BitSize + 7) >> 3) |
| 79 | if sigLength != expectedOctetLength { |
| 80 | return fmt.Errorf("signature length is %d octets long, should be %d", sigLength, expectedOctetLength) |
| 81 | } |
| 82 | |
| 83 | rBytes, sBytes := signature[:sigLength/2], signature[sigLength/2:] |
| 84 | r := new(big.Int).SetBytes(rBytes) |
| 85 | s := new(big.Int).SetBytes(sBytes) |
| 86 | |
| 87 | hasher := k.signatureAlgorithm.HashID().New() |
| 88 | _, err := io.Copy(hasher, data) |
| 89 | if err != nil { |
| 90 | return fmt.Errorf("error reading data to sign: %s", err) |
| 91 | } |
| 92 | hash := hasher.Sum(nil) |
| 93 | |
| 94 | if !ecdsa.Verify(k.PublicKey, hash, r, s) { |
| 95 | return errors.New("invalid signature") |
| 96 | } |
| 97 | |
| 98 | return nil |
| 99 | } |
| 100 | |
| 101 | // CryptoPublicKey returns the internal object which can be used as a |
| 102 | // crypto.PublicKey for use with other standard library operations. The type |
| 103 | // is either *rsa.PublicKey or *ecdsa.PublicKey |
| 104 | func (k *ecPublicKey) CryptoPublicKey() crypto.PublicKey { |
| 105 | return k.PublicKey |
| 106 | } |
| 107 | |
| 108 | func (k *ecPublicKey) toMap() map[string]interface{} { |
| 109 | jwk := make(map[string]interface{}) |
| 110 | for k, v := range k.extended { |
| 111 | jwk[k] = v |
| 112 | } |
| 113 | jwk["kty"] = k.KeyType() |
| 114 | jwk["kid"] = k.KeyID() |
| 115 | jwk["crv"] = k.CurveName() |
| 116 | |
| 117 | xBytes := k.X.Bytes() |
| 118 | yBytes := k.Y.Bytes() |
| 119 | octetLength := (k.Params().BitSize + 7) >> 3 |
| 120 | // MUST include leading zeros in the output so that x, y are each |
| 121 | // *octetLength* bytes long. |
| 122 | xBuf := make([]byte, octetLength-len(xBytes), octetLength) |
| 123 | yBuf := make([]byte, octetLength-len(yBytes), octetLength) |
| 124 | xBuf = append(xBuf, xBytes...) |
| 125 | yBuf = append(yBuf, yBytes...) |
| 126 | |
| 127 | jwk["x"] = joseBase64UrlEncode(xBuf) |
| 128 | jwk["y"] = joseBase64UrlEncode(yBuf) |
| 129 | |
| 130 | return jwk |
| 131 | } |
| 132 | |
| 133 | // MarshalJSON serializes this Public Key using the JWK JSON serialization format for |
| 134 | // elliptic curve keys. |
| 135 | func (k *ecPublicKey) MarshalJSON() (data []byte, err error) { |
| 136 | return json.Marshal(k.toMap()) |
| 137 | } |
| 138 | |
| 139 | // PEMBlock serializes this Public Key to DER-encoded PKIX format. |
| 140 | func (k *ecPublicKey) PEMBlock() (*pem.Block, error) { |
| 141 | derBytes, err := x509.MarshalPKIXPublicKey(k.PublicKey) |
| 142 | if err != nil { |
| 143 | return nil, fmt.Errorf("unable to serialize EC PublicKey to DER-encoded PKIX format: %s", err) |
| 144 | } |
| 145 | k.extended["kid"] = k.KeyID() // For display purposes. |
| 146 | return createPemBlock("PUBLIC KEY", derBytes, k.extended) |
| 147 | } |
| 148 | |
| 149 | func (k *ecPublicKey) AddExtendedField(field string, value interface{}) { |
| 150 | k.extended[field] = value |
| 151 | } |
| 152 | |
| 153 | func (k *ecPublicKey) GetExtendedField(field string) interface{} { |
| 154 | v, ok := k.extended[field] |
| 155 | if !ok { |
| 156 | return nil |
| 157 | } |
| 158 | return v |
| 159 | } |
| 160 | |
| 161 | func ecPublicKeyFromMap(jwk map[string]interface{}) (*ecPublicKey, error) { |
| 162 | // JWK key type (kty) has already been determined to be "EC". |
| 163 | // Need to extract 'crv', 'x', 'y', and 'kid' and check for |
| 164 | // consistency. |
| 165 | |
| 166 | // Get the curve identifier value. |
| 167 | crv, err := stringFromMap(jwk, "crv") |
| 168 | if err != nil { |
| 169 | return nil, fmt.Errorf("JWK EC Public Key curve identifier: %s", err) |
| 170 | } |
| 171 | |
| 172 | var ( |
| 173 | curve elliptic.Curve |
| 174 | sigAlg *signatureAlgorithm |
| 175 | ) |
| 176 | |
| 177 | switch { |
| 178 | case crv == "P-256": |
| 179 | curve = elliptic.P256() |
| 180 | sigAlg = es256 |
| 181 | case crv == "P-384": |
| 182 | curve = elliptic.P384() |
| 183 | sigAlg = es384 |
| 184 | case crv == "P-521": |
| 185 | curve = elliptic.P521() |
| 186 | sigAlg = es512 |
| 187 | default: |
| 188 | return nil, fmt.Errorf("JWK EC Public Key curve identifier not supported: %q\n", crv) |
| 189 | } |
| 190 | |
| 191 | // Get the X and Y coordinates for the public key point. |
| 192 | xB64Url, err := stringFromMap(jwk, "x") |
| 193 | if err != nil { |
| 194 | return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err) |
| 195 | } |
| 196 | x, err := parseECCoordinate(xB64Url, curve) |
| 197 | if err != nil { |
| 198 | return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err) |
| 199 | } |
| 200 | |
| 201 | yB64Url, err := stringFromMap(jwk, "y") |
| 202 | if err != nil { |
| 203 | return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err) |
| 204 | } |
| 205 | y, err := parseECCoordinate(yB64Url, curve) |
| 206 | if err != nil { |
| 207 | return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err) |
| 208 | } |
| 209 | |
| 210 | key := &ecPublicKey{ |
| 211 | PublicKey: &ecdsa.PublicKey{Curve: curve, X: x, Y: y}, |
| 212 | curveName: crv, signatureAlgorithm: sigAlg, |
| 213 | } |
| 214 | |
| 215 | // Key ID is optional too, but if it exists, it should match the key. |
| 216 | _, ok := jwk["kid"] |
| 217 | if ok { |
| 218 | kid, err := stringFromMap(jwk, "kid") |
| 219 | if err != nil { |
| 220 | return nil, fmt.Errorf("JWK EC Public Key ID: %s", err) |
| 221 | } |
| 222 | if kid != key.KeyID() { |
| 223 | return nil, fmt.Errorf("JWK EC Public Key ID does not match: %s", kid) |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | key.extended = jwk |
| 228 | |
| 229 | return key, nil |
| 230 | } |
| 231 | |
| 232 | /* |
| 233 | * EC DSA PRIVATE KEY |
| 234 | */ |
| 235 | |
| 236 | // ecPrivateKey implements a JWK Private Key using elliptic curve digital signature |
| 237 | // algorithms. |
| 238 | type ecPrivateKey struct { |
| 239 | ecPublicKey |
| 240 | *ecdsa.PrivateKey |
| 241 | } |
| 242 | |
| 243 | func fromECPrivateKey(cryptoPrivateKey *ecdsa.PrivateKey) (*ecPrivateKey, error) { |
| 244 | publicKey, err := fromECPublicKey(&cryptoPrivateKey.PublicKey) |
| 245 | if err != nil { |
| 246 | return nil, err |
| 247 | } |
| 248 | |
| 249 | return &ecPrivateKey{*publicKey, cryptoPrivateKey}, nil |
| 250 | } |
| 251 | |
| 252 | // PublicKey returns the Public Key data associated with this Private Key. |
| 253 | func (k *ecPrivateKey) PublicKey() PublicKey { |
| 254 | return &k.ecPublicKey |
| 255 | } |
| 256 | |
| 257 | func (k *ecPrivateKey) String() string { |
| 258 | return fmt.Sprintf("EC Private Key <%s>", k.KeyID()) |
| 259 | } |
| 260 | |
| 261 | // Sign signs the data read from the io.Reader using a signature algorithm supported |
| 262 | // by the elliptic curve private key. If the specified hashing algorithm is |
| 263 | // supported by this key, that hash function is used to generate the signature |
| 264 | // otherwise the the default hashing algorithm for this key is used. Returns |
| 265 | // the signature and the name of the JWK signature algorithm used, e.g., |
| 266 | // "ES256", "ES384", "ES512". |
| 267 | func (k *ecPrivateKey) Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) { |
| 268 | // Generate a signature of the data using the internal alg. |
| 269 | // The given hashId is only a suggestion, and since EC keys only support |
| 270 | // on signature/hash algorithm given the curve name, we disregard it for |
| 271 | // the elliptic curve JWK signature implementation. |
| 272 | hasher := k.signatureAlgorithm.HashID().New() |
| 273 | _, err = io.Copy(hasher, data) |
| 274 | if err != nil { |
| 275 | return nil, "", fmt.Errorf("error reading data to sign: %s", err) |
| 276 | } |
| 277 | hash := hasher.Sum(nil) |
| 278 | |
| 279 | r, s, err := ecdsa.Sign(rand.Reader, k.PrivateKey, hash) |
| 280 | if err != nil { |
| 281 | return nil, "", fmt.Errorf("error producing signature: %s", err) |
| 282 | } |
| 283 | rBytes, sBytes := r.Bytes(), s.Bytes() |
| 284 | octetLength := (k.ecPublicKey.Params().BitSize + 7) >> 3 |
| 285 | // MUST include leading zeros in the output |
| 286 | rBuf := make([]byte, octetLength-len(rBytes), octetLength) |
| 287 | sBuf := make([]byte, octetLength-len(sBytes), octetLength) |
| 288 | |
| 289 | rBuf = append(rBuf, rBytes...) |
| 290 | sBuf = append(sBuf, sBytes...) |
| 291 | |
| 292 | signature = append(rBuf, sBuf...) |
| 293 | alg = k.signatureAlgorithm.HeaderParam() |
| 294 | |
| 295 | return |
| 296 | } |
| 297 | |
| 298 | // CryptoPrivateKey returns the internal object which can be used as a |
| 299 | // crypto.PublicKey for use with other standard library operations. The type |
| 300 | // is either *rsa.PublicKey or *ecdsa.PublicKey |
| 301 | func (k *ecPrivateKey) CryptoPrivateKey() crypto.PrivateKey { |
| 302 | return k.PrivateKey |
| 303 | } |
| 304 | |
| 305 | func (k *ecPrivateKey) toMap() map[string]interface{} { |
| 306 | jwk := k.ecPublicKey.toMap() |
| 307 | |
| 308 | dBytes := k.D.Bytes() |
| 309 | // The length of this octet string MUST be ceiling(log-base-2(n)/8) |
| 310 | // octets (where n is the order of the curve). This is because the private |
| 311 | // key d must be in the interval [1, n-1] so the bitlength of d should be |
| 312 | // no larger than the bitlength of n-1. The easiest way to find the octet |
| 313 | // length is to take bitlength(n-1), add 7 to force a carry, and shift this |
| 314 | // bit sequence right by 3, which is essentially dividing by 8 and adding |
| 315 | // 1 if there is any remainder. Thus, the private key value d should be |
| 316 | // output to (bitlength(n-1)+7)>>3 octets. |
| 317 | n := k.ecPublicKey.Params().N |
| 318 | octetLength := (new(big.Int).Sub(n, big.NewInt(1)).BitLen() + 7) >> 3 |
| 319 | // Create a buffer with the necessary zero-padding. |
| 320 | dBuf := make([]byte, octetLength-len(dBytes), octetLength) |
| 321 | dBuf = append(dBuf, dBytes...) |
| 322 | |
| 323 | jwk["d"] = joseBase64UrlEncode(dBuf) |
| 324 | |
| 325 | return jwk |
| 326 | } |
| 327 | |
| 328 | // MarshalJSON serializes this Private Key using the JWK JSON serialization format for |
| 329 | // elliptic curve keys. |
| 330 | func (k *ecPrivateKey) MarshalJSON() (data []byte, err error) { |
| 331 | return json.Marshal(k.toMap()) |
| 332 | } |
| 333 | |
| 334 | // PEMBlock serializes this Private Key to DER-encoded PKIX format. |
| 335 | func (k *ecPrivateKey) PEMBlock() (*pem.Block, error) { |
| 336 | derBytes, err := x509.MarshalECPrivateKey(k.PrivateKey) |
| 337 | if err != nil { |
| 338 | return nil, fmt.Errorf("unable to serialize EC PrivateKey to DER-encoded PKIX format: %s", err) |
| 339 | } |
| 340 | k.extended["keyID"] = k.KeyID() // For display purposes. |
| 341 | return createPemBlock("EC PRIVATE KEY", derBytes, k.extended) |
| 342 | } |
| 343 | |
| 344 | func ecPrivateKeyFromMap(jwk map[string]interface{}) (*ecPrivateKey, error) { |
| 345 | dB64Url, err := stringFromMap(jwk, "d") |
| 346 | if err != nil { |
| 347 | return nil, fmt.Errorf("JWK EC Private Key: %s", err) |
| 348 | } |
| 349 | |
| 350 | // JWK key type (kty) has already been determined to be "EC". |
| 351 | // Need to extract the public key information, then extract the private |
| 352 | // key value 'd'. |
| 353 | publicKey, err := ecPublicKeyFromMap(jwk) |
| 354 | if err != nil { |
| 355 | return nil, err |
| 356 | } |
| 357 | |
| 358 | d, err := parseECPrivateParam(dB64Url, publicKey.Curve) |
| 359 | if err != nil { |
| 360 | return nil, fmt.Errorf("JWK EC Private Key d-param: %s", err) |
| 361 | } |
| 362 | |
| 363 | key := &ecPrivateKey{ |
| 364 | ecPublicKey: *publicKey, |
| 365 | PrivateKey: &ecdsa.PrivateKey{ |
| 366 | PublicKey: *publicKey.PublicKey, |
| 367 | D: d, |
| 368 | }, |
| 369 | } |
| 370 | |
| 371 | return key, nil |
| 372 | } |
| 373 | |
| 374 | /* |
| 375 | * Key Generation Functions. |
| 376 | */ |
| 377 | |
| 378 | func generateECPrivateKey(curve elliptic.Curve) (k *ecPrivateKey, err error) { |
| 379 | k = new(ecPrivateKey) |
| 380 | k.PrivateKey, err = ecdsa.GenerateKey(curve, rand.Reader) |
| 381 | if err != nil { |
| 382 | return nil, err |
| 383 | } |
| 384 | |
| 385 | k.ecPublicKey.PublicKey = &k.PrivateKey.PublicKey |
| 386 | k.extended = make(map[string]interface{}) |
| 387 | |
| 388 | return |
| 389 | } |
| 390 | |
| 391 | // GenerateECP256PrivateKey generates a key pair using elliptic curve P-256. |
| 392 | func GenerateECP256PrivateKey() (PrivateKey, error) { |
| 393 | k, err := generateECPrivateKey(elliptic.P256()) |
| 394 | if err != nil { |
| 395 | return nil, fmt.Errorf("error generating EC P-256 key: %s", err) |
| 396 | } |
| 397 | |
| 398 | k.curveName = "P-256" |
| 399 | k.signatureAlgorithm = es256 |
| 400 | |
| 401 | return k, nil |
| 402 | } |
| 403 | |
| 404 | // GenerateECP384PrivateKey generates a key pair using elliptic curve P-384. |
| 405 | func GenerateECP384PrivateKey() (PrivateKey, error) { |
| 406 | k, err := generateECPrivateKey(elliptic.P384()) |
| 407 | if err != nil { |
| 408 | return nil, fmt.Errorf("error generating EC P-384 key: %s", err) |
| 409 | } |
| 410 | |
| 411 | k.curveName = "P-384" |
| 412 | k.signatureAlgorithm = es384 |
| 413 | |
| 414 | return k, nil |
| 415 | } |
| 416 | |
| 417 | // GenerateECP521PrivateKey generates aß key pair using elliptic curve P-521. |
| 418 | func GenerateECP521PrivateKey() (PrivateKey, error) { |
| 419 | k, err := generateECPrivateKey(elliptic.P521()) |
| 420 | if err != nil { |
| 421 | return nil, fmt.Errorf("error generating EC P-521 key: %s", err) |
| 422 | } |
| 423 | |
| 424 | k.curveName = "P-521" |
| 425 | k.signatureAlgorithm = es512 |
| 426 | |
| 427 | return k, nil |
| 428 | } |