tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ecp_secp256r1.c (9306B)


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