• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // This is an implementation of the crypto operations that uses boringssl. The
16 // algorithms used are SHA512, HKDF-SHA512, and ECDSA P384-SHA384.
17 
18 #include "dice/boringssl_ecdsa_utils.h"
19 
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include "openssl/bn.h"
25 #include "openssl/crypto.h"
26 #include "openssl/ec.h"
27 #include "openssl/ec_key.h"
28 #include "openssl/ecdsa.h"
29 #include "openssl/evp.h"
30 #include "openssl/hkdf.h"
31 #include "openssl/hmac.h"
32 #include "openssl/is_boringssl.h"
33 #include "openssl/sha.h"
34 
hmac(uint8_t k[64],uint8_t in[64],uint8_t * out,unsigned int out_len)35 static int hmac(uint8_t k[64], uint8_t in[64], uint8_t *out,
36                 unsigned int out_len) {
37   int ret = 0;
38 
39   if (out_len > 64 || out_len < 0) {
40     goto out;
41   }
42   HMAC_CTX ctx;
43   HMAC_CTX_init(&ctx);
44   if (1 != HMAC_Init_ex(&ctx, k, 64, EVP_sha512(), NULL /* impl */)) {
45     goto out;
46   }
47   if (1 != HMAC_Update(&ctx, in, 64)) {
48     goto out;
49   }
50   ret = HMAC_Final(&ctx, out, &out_len);
51   HMAC_CTX_cleanup(&ctx);
52 
53 out:
54   return ret;
55 }
56 
hmac3(uint8_t k[64],uint8_t in1[64],uint8_t in2,const uint8_t * in3,unsigned int in3_len,uint8_t out[64])57 static int hmac3(uint8_t k[64], uint8_t in1[64], uint8_t in2,
58                   const uint8_t *in3, unsigned int in3_len, uint8_t out[64]) {
59   int ret = 0;
60 
61   HMAC_CTX ctx;
62   HMAC_CTX_init(&ctx);
63   if (1 != HMAC_Init_ex(&ctx, k, 64, EVP_sha512(), NULL /* impl */)) {
64     goto out;
65   }
66   if (1 != HMAC_Update(&ctx, in1, 64)) {
67     goto out;
68   }
69   if (1 != HMAC_Update(&ctx, &in2, 1)) {
70     goto out;
71   }
72   if (in3 != NULL && in3_len > 0) {
73     if (1 != HMAC_Update(&ctx, in3, in3_len)) {
74       goto out;
75     }
76   }
77   unsigned int out_len = 64;
78   ret = HMAC_Final(&ctx, out, &out_len);
79   HMAC_CTX_cleanup(&ctx);
80 
81 out:
82   return ret;
83 }
84 
85 // Algorithm from section 3.2 of IETF RFC6979
derivePrivateKey(const EC_GROUP * group,const uint8_t * seed,size_t seed_size,uint8_t * private_key,size_t private_key_len)86 static BIGNUM *derivePrivateKey(const EC_GROUP *group, const uint8_t *seed,
87                                 size_t seed_size, uint8_t *private_key,
88                                 size_t private_key_len) {
89   BIGNUM *candidate = NULL;
90   uint8_t v[64];
91   uint8_t k[64];
92   memset(v, 1, 64);
93   memset(k, 0, 64);
94 
95   if (1 != hmac3(k, v, 0x00, seed, (unsigned int)seed_size, k)) {
96     goto err;
97   }
98   if (1 != hmac(k, v, v, sizeof(v))) {
99     goto err;
100   }
101   if (1 != hmac3(k, v, 0x01, seed, (unsigned int)seed_size, k)) {
102     goto err;
103   }
104   do {
105     if (1 != hmac(k, v, v, sizeof(v))) {
106       goto err;
107     }
108     if (1 != hmac(k, v, private_key, private_key_len)) {
109       goto err;
110     }
111     if (1 != hmac3(k, v, 0x00, NULL, 0, k)) {
112       goto err;
113     }
114     candidate = BN_bin2bn(private_key, private_key_len, NULL);
115     if (!candidate) {
116       goto err;
117     }
118   } while (BN_cmp(candidate, EC_GROUP_get0_order(group)) >= 0 ||
119            BN_is_zero(candidate));
120   goto out;
121 
122 err:
123   BN_clear_free(candidate);
124   candidate = NULL;
125 out:
126   return candidate;
127 }
128 
P384KeypairFromSeed(uint8_t public_key[P384_PUBLIC_KEY_SIZE],uint8_t private_key[P384_PRIVATE_KEY_SIZE],const uint8_t seed[DICE_PRIVATE_KEY_SEED_SIZE])129 int P384KeypairFromSeed(uint8_t public_key[P384_PUBLIC_KEY_SIZE],
130                         uint8_t private_key[P384_PRIVATE_KEY_SIZE],
131                         const uint8_t seed[DICE_PRIVATE_KEY_SEED_SIZE]) {
132   int ret = 0;
133   EC_POINT *publicKey = NULL;
134   BIGNUM *pD = NULL;
135   BIGNUM *x = NULL;
136   BIGNUM *y = NULL;
137 
138   EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1);
139   if (!key) {
140     goto out;
141   }
142   const EC_GROUP *group = EC_KEY_get0_group(key);
143   if (!group) {
144     goto out;
145   }
146   publicKey = EC_POINT_new(group);
147   if (!publicKey) {
148     goto out;
149   }
150 
151   pD = derivePrivateKey(group, seed, DICE_PRIVATE_KEY_SEED_SIZE, private_key,
152                                 P384_PRIVATE_KEY_SIZE);
153   if (!pD) {
154     goto out;
155   }
156   if (1 != BN_bn2bin_padded(private_key, P384_PRIVATE_KEY_SIZE, pD)) {
157     goto out;
158   }
159   if (1 != EC_KEY_set_private_key(key, pD)) {
160     goto out;
161   }
162   if (1 != EC_POINT_mul(group, publicKey, pD, NULL, NULL, NULL)) {
163     goto out;
164   }
165   x = BN_new();
166   if (!x) {
167     goto out;
168   }
169   y = BN_new();
170   if (!y) {
171     goto out;
172   }
173   if (1 != EC_POINT_get_affine_coordinates_GFp(group, publicKey, x, y, NULL)) {
174     goto out;
175   }
176   if (BN_num_bytes(x) > P384_PRIVATE_KEY_SIZE) {
177     goto out;
178   }
179   BN_bn2bin(x, &public_key[0]);
180   if (BN_num_bytes(y) > P384_PRIVATE_KEY_SIZE) {
181     goto out;
182   }
183   BN_bn2bin(y, &public_key[P384_PRIVATE_KEY_SIZE]);
184   ret = 1;
185 
186 out:
187   EC_POINT_free(publicKey);
188   BN_clear_free(x);
189   BN_clear_free(y);
190   EC_KEY_free(key);
191   BN_clear_free(pD);
192 
193   return ret;
194 }
195 
P384Sign(uint8_t signature[P384_SIGNATURE_SIZE],const uint8_t * message,size_t message_size,const uint8_t private_key[P384_PRIVATE_KEY_SIZE])196 int P384Sign(uint8_t signature[P384_SIGNATURE_SIZE], const uint8_t *message,
197              size_t message_size,
198              const uint8_t private_key[P384_PRIVATE_KEY_SIZE]) {
199   int ret = 0;
200   BIGNUM *pD = NULL;
201   EC_KEY *key = NULL;
202   uint8_t output[48];
203   ECDSA_SIG *sig = NULL;
204 
205   pD = BN_bin2bn(private_key, P384_PRIVATE_KEY_SIZE, NULL);
206   if (!pD) {
207     goto out;
208   }
209   key = EC_KEY_new_by_curve_name(NID_secp384r1);
210   if (!key) {
211     goto out;
212   }
213   if (1 != EC_KEY_set_private_key(key, pD)) {
214     goto out;
215   }
216   SHA384(message, message_size, output);
217   sig = ECDSA_do_sign(output, 48, key);
218   if (!sig) {
219     goto out;
220   }
221 
222   if (BN_num_bytes(sig->r) > P384_PRIVATE_KEY_SIZE) {
223     goto out;
224   }
225   BN_bn2bin(sig->r, &signature[0]);
226   if (BN_num_bytes(sig->s) > P384_PRIVATE_KEY_SIZE) {
227     goto out;
228   }
229   BN_bn2bin(sig->s, &signature[P384_PRIVATE_KEY_SIZE]);
230   ret = 1;
231 
232 out:
233   EC_KEY_free(key);
234   BN_clear_free(pD);
235   ECDSA_SIG_free(sig);
236   return ret;
237 }
238 
P384Verify(const uint8_t * message,size_t message_size,const uint8_t signature[P384_SIGNATURE_SIZE],const uint8_t public_key[P384_PUBLIC_KEY_SIZE])239 int P384Verify(const uint8_t *message, size_t message_size,
240                const uint8_t signature[P384_SIGNATURE_SIZE],
241                const uint8_t public_key[P384_PUBLIC_KEY_SIZE]) {
242   int ret = 0;
243   uint8_t output[48];
244   EC_KEY *key = NULL;
245   BIGNUM *bn_ret = NULL;
246   BIGNUM *x = NULL;
247   BIGNUM *y = NULL;
248   ECDSA_SIG *sig = NULL;
249 
250   SHA384(message, message_size, output);
251   key = EC_KEY_new_by_curve_name(NID_secp384r1);
252   if (!key) {
253     goto out;
254   }
255   x = BN_new();
256   if (!x) {
257     goto out;
258   }
259   bn_ret = BN_bin2bn(&public_key[0], P384_PUBLIC_KEY_SIZE / 2, x);
260   if (!bn_ret) {
261     goto out;
262   }
263   y = BN_new();
264   if (!y) {
265     goto out;
266   }
267   bn_ret = BN_bin2bn(&public_key[P384_PUBLIC_KEY_SIZE / 2], P384_PUBLIC_KEY_SIZE / 2, y);
268   if (!bn_ret) {
269     goto out;
270   }
271   if (1 != EC_KEY_set_public_key_affine_coordinates(key, x, y)) {
272     goto out;
273   }
274 
275 
276   sig = ECDSA_SIG_new();
277   if (!sig) {
278     goto out;
279   }
280   bn_ret = BN_bin2bn(&signature[0], P384_SIGNATURE_SIZE / 2, sig->r);
281   if (!bn_ret) {
282     goto out;
283   }
284   bn_ret = BN_bin2bn(&signature[P384_SIGNATURE_SIZE / 2], P384_SIGNATURE_SIZE / 2,
285             sig->s);
286   if (!bn_ret) {
287     goto out;
288   }
289   ret = ECDSA_do_verify(output, 48, sig, key);
290 
291 out:
292   BN_clear_free(y);
293   BN_clear_free(x);
294   EC_KEY_free(key);
295   ECDSA_SIG_free(sig);
296   return ret;
297 }
298