ecp_secp521r1.c (9839B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifdef FREEBL_NO_DEPEND 6 #include "../stubs.h" 7 #endif 8 9 #include "ecl-priv.h" 10 #include "secitem.h" 11 #include "secerr.h" 12 #include "secmpi.h" 13 #include "../verified/Hacl_P521.h" 14 15 /* 16 * Point Validation for P-521. 17 */ 18 19 SECStatus 20 ec_secp521r1_pt_validate(const SECItem *pt) 21 { 22 SECStatus res = SECSuccess; 23 if (!pt || !pt->data) { 24 PORT_SetError(SEC_ERROR_INVALID_ARGS); 25 res = SECFailure; 26 return res; 27 } 28 29 if (pt->len != 133) { 30 PORT_SetError(SEC_ERROR_BAD_KEY); 31 res = SECFailure; 32 return res; 33 } 34 35 if (pt->data[0] != EC_POINT_FORM_UNCOMPRESSED) { 36 PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); 37 res = SECFailure; 38 return res; 39 } 40 41 #ifndef UNSAFE_FUZZER_MODE 42 bool b = Hacl_P521_validate_public_key(pt->data + 1); 43 #else 44 bool b = PR_TRUE; 45 #endif 46 47 if (!b) { 48 PORT_SetError(SEC_ERROR_BAD_KEY); 49 res = SECFailure; 50 } 51 return res; 52 } 53 54 /* 55 * Scalar Validation for P-521. 56 */ 57 58 SECStatus 59 ec_secp521r1_scalar_validate(const SECItem *scalar) 60 { 61 SECStatus res = SECSuccess; 62 if (!scalar || !scalar->data) { 63 PORT_SetError(SEC_ERROR_INVALID_ARGS); 64 res = SECFailure; 65 return res; 66 } 67 68 if (scalar->len != 66) { 69 PORT_SetError(SEC_ERROR_BAD_KEY); 70 res = SECFailure; 71 return res; 72 } 73 74 #ifndef UNSAFE_FUZZER_MODE 75 bool b = Hacl_P521_validate_private_key(scalar->data); 76 #else 77 bool b = PR_TRUE; 78 #endif 79 80 if (!b) { 81 PORT_SetError(SEC_ERROR_BAD_KEY); 82 res = SECFailure; 83 } 84 return res; 85 } 86 87 /* 88 * Scalar multiplication for P-521. 89 * If P == NULL, the base point is used. 90 * Returns X = k*P 91 */ 92 93 SECStatus 94 ec_secp521r1_pt_mul(SECItem *X, SECItem *k, SECItem *P) 95 { 96 SECStatus res = SECSuccess; 97 if (!P) { 98 uint8_t derived[132] = { 0 }; 99 100 if (!X || !k || !X->data || !k->data || 101 X->len < 133 || k->len != 66) { 102 PORT_SetError(SEC_ERROR_INVALID_ARGS); 103 res = SECFailure; 104 return res; 105 } 106 107 #ifndef UNSAFE_FUZZER_MODE 108 bool b = Hacl_P521_dh_initiator(derived, k->data); 109 #else 110 bool b = PR_TRUE; 111 #endif 112 113 if (!b) { 114 PORT_SetError(SEC_ERROR_BAD_KEY); 115 res = SECFailure; 116 return res; 117 } 118 119 X->len = 133; 120 X->data[0] = EC_POINT_FORM_UNCOMPRESSED; 121 memcpy(X->data + 1, derived, 132); 122 123 } else { 124 uint8_t full_key[66] = { 0 }; 125 uint8_t *key; 126 uint8_t derived[132] = { 0 }; 127 128 if (!X || !k || !P || !X->data || !k->data || !P->data || 129 X->len < 66 || P->len != 133 || 130 P->data[0] != EC_POINT_FORM_UNCOMPRESSED) { 131 PORT_SetError(SEC_ERROR_INVALID_ARGS); 132 res = SECFailure; 133 return res; 134 } 135 136 /* We consider keys of up to size 66, or of size 67 with a single leading 0 */ 137 if (k->len < 66) { 138 memcpy(full_key + 66 - k->len, k->data, k->len); 139 key = full_key; 140 } else if (k->len == 66) { 141 key = k->data; 142 } else if (k->len == 67 && k->data[0] == 0) { 143 key = k->data + 1; 144 } else { 145 PORT_SetError(SEC_ERROR_INVALID_ARGS); 146 res = SECFailure; 147 return res; 148 } 149 150 #ifndef UNSAFE_FUZZER_MODE 151 bool b = Hacl_P521_dh_responder(derived, P->data + 1, key); 152 #else 153 bool b = key != NULL; /* Avoiding unused variable warnings */ 154 #endif 155 156 if (!b) { 157 PORT_SetError(SEC_ERROR_BAD_KEY); 158 res = SECFailure; 159 return res; 160 } 161 162 X->len = 66; 163 memcpy(X->data, derived, 66); 164 } 165 166 return res; 167 } 168 169 /* 170 * ECDSA Signature for P-521 171 */ 172 173 SECStatus 174 ec_secp521r1_sign_digest(ECPrivateKey *ecPrivKey, SECItem *signature, 175 const SECItem *digest, const unsigned char *kb, 176 const unsigned int kblen) 177 { 178 SECStatus res = SECSuccess; 179 180 if (!ecPrivKey || !signature || !digest || !kb || 181 !ecPrivKey->privateValue.data || 182 !signature->data || !digest->data || 183 ecPrivKey->ecParams.name != ECCurve_NIST_P521) { 184 PORT_SetError(SEC_ERROR_INVALID_ARGS); 185 return SECFailure; 186 } 187 188 if (kblen == 0 || digest->len == 0 || signature->len < 132) { 189 PORT_SetError(SEC_ERROR_INPUT_LEN); 190 return SECFailure; 191 } 192 193 // Private keys should be 66 bytes, but some software trims leading zeros, 194 // and some software produces 67 byte keys with a leading zero. We'll 195 // accept these variants. 196 uint8_t padded_key_data[66] = { 0 }; 197 uint8_t *key; 198 SECItem *privKey = &ecPrivKey->privateValue; 199 if (privKey->len == 66) { 200 key = privKey->data; 201 } else if (privKey->len == 67 && privKey->data[0] == 0) { 202 key = privKey->data + 1; 203 } else if (privKey->len < 66) { 204 memcpy(padded_key_data + 66 - privKey->len, privKey->data, privKey->len); 205 key = padded_key_data; 206 } else { 207 PORT_SetError(SEC_ERROR_INPUT_LEN); 208 return SECFailure; 209 } 210 211 uint8_t hash[66] = { 0 }; 212 if (digest->len < 66) { 213 memcpy(hash + 66 - digest->len, digest->data, digest->len); 214 } else { 215 // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n). 216 hash[0] = digest->data[0] >> 7; 217 for (size_t i = 1; i < 66; i++) { 218 hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7); 219 } 220 } 221 222 uint8_t nonce[66] = { 0 }; 223 if (kblen < 66) { 224 memcpy(nonce + 66 - kblen, kb, kblen); 225 } else { 226 memcpy(nonce, kb, 66); 227 } 228 229 #ifndef UNSAFE_FUZZER_MODE 230 bool b = Hacl_P521_ecdsa_sign_p521_without_hash( 231 signature->data, 66, hash, key, nonce); 232 #else 233 bool b = key != NULL; /* Avoiding unused variable warnings */ 234 #endif 235 236 if (!b) { 237 PORT_SetError(SEC_ERROR_BAD_KEY); 238 res = SECFailure; 239 return res; 240 } 241 242 signature->len = 132; 243 return res; 244 } 245 246 /* 247 * ECDSA Signature Verification for P-521 248 */ 249 250 SECStatus 251 ec_secp521r1_verify_digest(ECPublicKey *key, const SECItem *signature, 252 const SECItem *digest) 253 { 254 SECStatus res = SECSuccess; 255 256 if (!key || !signature || !digest || 257 !key->publicValue.data || 258 !signature->data || !digest->data || 259 key->ecParams.name != ECCurve_NIST_P521) { 260 PORT_SetError(SEC_ERROR_INVALID_ARGS); 261 res = SECFailure; 262 return res; 263 } 264 265 if (signature->len == 0 || signature->len % 2 != 0 || 266 signature->len > 132 || digest->len == 0 || 267 key->publicValue.len != 133) { 268 PORT_SetError(SEC_ERROR_INPUT_LEN); 269 res = SECFailure; 270 return res; 271 } 272 273 if (key->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) { 274 PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); 275 res = SECFailure; 276 return res; 277 } 278 279 // Signatures should be 132 bytes, but some software produces short signatures. 280 // Pad components with zeros if necessary. 281 uint8_t paddedSigData[132] = { 0 }; 282 uint8_t *sig; 283 if (signature->len != 132) { 284 size_t split = signature->len / 2; 285 286 memcpy(paddedSigData + 66 - split, signature->data, split); 287 memcpy(paddedSigData + 132 - split, signature->data + split, split); 288 289 sig = paddedSigData; 290 } else { 291 sig = signature->data; 292 } 293 294 uint8_t hash[66] = { 0 }; 295 if (digest->len < 66) { 296 memcpy(hash + 66 - digest->len, digest->data, digest->len); 297 } else { 298 // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n). 299 hash[0] = digest->data[0] >> 7; 300 for (size_t i = 1; i < 66; i++) { 301 hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7); 302 } 303 } 304 305 #ifndef UNSAFE_FUZZER_MODE 306 bool b = Hacl_P521_ecdsa_verif_without_hash( 307 66, hash, key->publicValue.data + 1, sig, sig + 66); 308 #else 309 bool b = sig != NULL; /* Avoiding unused variable warnings */ 310 #endif 311 312 if (!b) { 313 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 314 res = SECFailure; 315 return res; 316 } 317 318 return res; 319 } 320 321 /* 322 Point decompression for P-521. 323 324 publicCompressed must be 67 bytes (1 byte for a sign and 66 bytes for the x coordinate. 325 publicUncompressed must be 132 bytes (66 * 2). 326 The function returns SECSuccess if the decompression was success and the decompresse 327 point is a valid P-521 curve point. 328 */ 329 330 SECStatus 331 ec_secp521r1_decompress(const SECItem *publicCompressed, SECItem *publicUncompressed) 332 { 333 if (!publicCompressed || !publicCompressed->data) { 334 PORT_SetError(SEC_ERROR_INVALID_ARGS); 335 return SECFailure; 336 } 337 338 if (publicCompressed->len != 67) { 339 PORT_SetError(SEC_ERROR_BAD_KEY); 340 return SECFailure; 341 } 342 343 if (!publicUncompressed || !publicUncompressed->data) { 344 PORT_SetError(SEC_ERROR_INVALID_ARGS); 345 return SECFailure; 346 } 347 348 if (publicUncompressed->len != 133) { 349 PORT_SetError(SEC_ERROR_INVALID_ARGS); 350 return SECFailure; 351 } 352 353 if (publicCompressed->data[0] != EC_POINT_FORM_COMPRESSED_Y0 && 354 publicCompressed->data[0] != EC_POINT_FORM_COMPRESSED_Y1) { 355 PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); 356 return SECFailure; 357 } 358 359 bool b = Hacl_P521_compressed_to_raw(publicCompressed->data, publicUncompressed->data + 1); 360 361 if (!b) { 362 PORT_SetError(SEC_ERROR_BAD_KEY); 363 return SECFailure; 364 } 365 366 publicUncompressed->data[0] = EC_POINT_FORM_UNCOMPRESSED; 367 return SECSuccess; 368 }