tor-browser

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

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 }