| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <openssl/ec.h> | 5 #include <openssl/ec.h> |
| 6 #include <openssl/ecdh.h> | 6 #include <openssl/ecdh.h> |
| 7 #include <openssl/evp.h> | 7 #include <openssl/evp.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "content/child/webcrypto/algorithm_implementation.h" | 10 #include "content/child/webcrypto/algorithm_implementation.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 blink::WebCryptoKeyUsageDeriveBits) {} | 42 blink::WebCryptoKeyUsageDeriveBits) {} |
| 43 | 43 |
| 44 const char* GetJwkAlgorithm( | 44 const char* GetJwkAlgorithm( |
| 45 const blink::WebCryptoNamedCurve curve) const override { | 45 const blink::WebCryptoNamedCurve curve) const override { |
| 46 // JWK import for ECDH does not enforce any required value for "alg". | 46 // JWK import for ECDH does not enforce any required value for "alg". |
| 47 return ""; | 47 return ""; |
| 48 } | 48 } |
| 49 | 49 |
| 50 Status DeriveBits(const blink::WebCryptoAlgorithm& algorithm, | 50 Status DeriveBits(const blink::WebCryptoAlgorithm& algorithm, |
| 51 const blink::WebCryptoKey& base_key, | 51 const blink::WebCryptoKey& base_key, |
| 52 unsigned int length_bits, | 52 bool has_optional_length_bits, |
| 53 unsigned int optional_length_bits, |
| 53 std::vector<uint8_t>* derived_bytes) const override { | 54 std::vector<uint8_t>* derived_bytes) const override { |
| 54 if (base_key.type() != blink::WebCryptoKeyTypePrivate) | 55 if (base_key.type() != blink::WebCryptoKeyTypePrivate) |
| 55 return Status::ErrorUnexpectedKeyType(); | 56 return Status::ErrorUnexpectedKeyType(); |
| 56 | 57 |
| 57 // Verify the "publicKey" parameter. The only guarantee from Blink is that | 58 // Verify the "publicKey" parameter. The only guarantee from Blink is that |
| 58 // it is a valid WebCryptoKey, but it could be any type. | 59 // it is a valid WebCryptoKey, but it could be any type. |
| 59 const blink::WebCryptoKey& public_key = | 60 const blink::WebCryptoKey& public_key = |
| 60 algorithm.ecdhKeyDeriveParams()->publicKey(); | 61 algorithm.ecdhKeyDeriveParams()->publicKey(); |
| 61 | 62 |
| 62 if (public_key.type() != blink::WebCryptoKeyTypePublic) | 63 if (public_key.type() != blink::WebCryptoKeyTypePublic) |
| 63 return Status::ErrorEcdhPublicKeyWrongType(); | 64 return Status::ErrorEcdhPublicKeyWrongType(); |
| 64 | 65 |
| 65 // Make sure it is an EC key. | 66 // Make sure it is an EC key. |
| 66 if (!public_key.algorithm().ecParams()) | 67 if (!public_key.algorithm().ecParams()) |
| 67 return Status::ErrorEcdhPublicKeyWrongType(); | 68 return Status::ErrorEcdhPublicKeyWrongType(); |
| 68 | 69 |
| 69 // TODO(eroman): This is not described by the spec: | 70 // TODO(eroman): This is not described by the spec: |
| 70 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=27404 | 71 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=27404 |
| 71 if (public_key.algorithm().id() != blink::WebCryptoAlgorithmIdEcdh) | 72 if (public_key.algorithm().id() != blink::WebCryptoAlgorithmIdEcdh) |
| 72 return Status::ErrorEcdhPublicKeyWrongAlgorithm(); | 73 return Status::ErrorEcdhPublicKeyWrongAlgorithm(); |
| 73 | 74 |
| 74 // The public and private keys come from different key pairs, however their | 75 // The public and private keys come from different key pairs, however their |
| 75 // curves must match. | 76 // curves must match. |
| 76 if (public_key.algorithm().ecParams()->namedCurve() != | 77 if (public_key.algorithm().ecParams()->namedCurve() != |
| 77 base_key.algorithm().ecParams()->namedCurve()) { | 78 base_key.algorithm().ecParams()->namedCurve()) { |
| 78 return Status::ErrorEcdhCurveMismatch(); | 79 return Status::ErrorEcdhCurveMismatch(); |
| 79 } | 80 } |
| 80 | 81 |
| 81 // Handle the empty length case now to avoid calling an undefined | |
| 82 // |&derived_bytes->front()| later. | |
| 83 if (length_bits == 0) { | |
| 84 derived_bytes->clear(); | |
| 85 return Status::Success(); | |
| 86 } | |
| 87 | |
| 88 crypto::ScopedEC_KEY public_key_ec( | 82 crypto::ScopedEC_KEY public_key_ec( |
| 89 EVP_PKEY_get1_EC_KEY(AsymKeyOpenSsl::Cast(public_key)->key())); | 83 EVP_PKEY_get1_EC_KEY(AsymKeyOpenSsl::Cast(public_key)->key())); |
| 90 | 84 |
| 91 const EC_POINT* public_key_point = | 85 const EC_POINT* public_key_point = |
| 92 EC_KEY_get0_public_key(public_key_ec.get()); | 86 EC_KEY_get0_public_key(public_key_ec.get()); |
| 93 | 87 |
| 94 crypto::ScopedEC_KEY private_key_ec( | 88 crypto::ScopedEC_KEY private_key_ec( |
| 95 EVP_PKEY_get1_EC_KEY(AsymKeyOpenSsl::Cast(base_key)->key())); | 89 EVP_PKEY_get1_EC_KEY(AsymKeyOpenSsl::Cast(base_key)->key())); |
| 96 | 90 |
| 97 // The size of the shared secret is the field size in bytes (rounded up). | 91 // The size of the shared secret is the field size in bytes (rounded up). |
| 98 // Note that, if rounding was required, the most significant bits of the | 92 // Note that, if rounding was required, the most significant bits of the |
| 99 // secret are zero. So for P-521, the maximum length is 528 bits, not 521. | 93 // secret are zero. So for P-521, the maximum length is 528 bits, not 521. |
| 100 int field_size_bytes = NumBitsToBytes( | 94 int field_size_bytes = NumBitsToBytes( |
| 101 EC_GROUP_get_degree(EC_KEY_get0_group(private_key_ec.get()))); | 95 EC_GROUP_get_degree(EC_KEY_get0_group(private_key_ec.get()))); |
| 102 | 96 |
| 97 // If a desired key length was not specified, default to the field size |
| 98 // (rounded up to nearest byte). |
| 99 unsigned int length_bits = |
| 100 has_optional_length_bits ? optional_length_bits : field_size_bytes * 8; |
| 101 |
| 102 // Handle the empty length case now to avoid calling an undefined |
| 103 // |&derived_bytes->front()| later. |
| 104 if (length_bits == 0) { |
| 105 derived_bytes->clear(); |
| 106 return Status::Success(); |
| 107 } |
| 108 |
| 103 if (length_bits > static_cast<unsigned int>(field_size_bytes * 8)) | 109 if (length_bits > static_cast<unsigned int>(field_size_bytes * 8)) |
| 104 return Status::ErrorEcdhLengthTooBig(field_size_bytes * 8); | 110 return Status::ErrorEcdhLengthTooBig(field_size_bytes * 8); |
| 105 | 111 |
| 106 // Resize to target length in bytes (BoringSSL can operate on a shorter | 112 // Resize to target length in bytes (BoringSSL can operate on a shorter |
| 107 // buffer than field_size_bytes). | 113 // buffer than field_size_bytes). |
| 108 derived_bytes->resize(NumBitsToBytes(length_bits)); | 114 derived_bytes->resize(NumBitsToBytes(length_bits)); |
| 109 | 115 |
| 110 int result = | 116 int result = |
| 111 ECDH_compute_key(&derived_bytes->front(), derived_bytes->size(), | 117 ECDH_compute_key(&derived_bytes->front(), derived_bytes->size(), |
| 112 public_key_point, private_key_ec.get(), 0); | 118 public_key_point, private_key_ec.get(), 0); |
| 113 if (result < 0 || static_cast<size_t>(result) != derived_bytes->size()) | 119 if (result < 0 || static_cast<size_t>(result) != derived_bytes->size()) |
| 114 return Status::OperationError(); | 120 return Status::OperationError(); |
| 115 | 121 |
| 116 TruncateToBitLength(length_bits, derived_bytes); | 122 TruncateToBitLength(length_bits, derived_bytes); |
| 117 return Status::Success(); | 123 return Status::Success(); |
| 118 } | 124 } |
| 119 }; | 125 }; |
| 120 | 126 |
| 121 } // namespace | 127 } // namespace |
| 122 | 128 |
| 123 AlgorithmImplementation* CreatePlatformEcdhImplementation() { | 129 AlgorithmImplementation* CreatePlatformEcdhImplementation() { |
| 124 return new EcdhImplementation; | 130 return new EcdhImplementation; |
| 125 } | 131 } |
| 126 | 132 |
| 127 } // namespace webcrypto | 133 } // namespace webcrypto |
| 128 | 134 |
| 129 } // namespace content | 135 } // namespace content |
| OLD | NEW |