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 |