tor-browser

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

dsautil.c (7843B)


      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 #include "cryptohi.h"
      5 #include "secasn1.h"
      6 #include "secitem.h"
      7 #include "prerr.h"
      8 
      9 #ifndef DSA1_SUBPRIME_LEN
     10 #define DSA1_SUBPRIME_LEN 20 /* bytes */
     11 #endif
     12 
     13 typedef struct {
     14    SECItem r;
     15    SECItem s;
     16 } DSA_ASN1Signature;
     17 
     18 const SEC_ASN1Template DSA_SignatureTemplate[] = {
     19    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(DSA_ASN1Signature) },
     20    { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature, r) },
     21    { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature, s) },
     22    { 0 }
     23 };
     24 
     25 /* Input is variable length multi-byte integer, MSB first (big endian).
     26 ** Most signficant bit of first byte is NOT treated as a sign bit.
     27 ** May be one or more leading bytes of zeros.
     28 ** Output is variable length multi-byte integer, MSB first (big endian).
     29 ** Most significant bit of first byte will be zero (positive sign bit)
     30 ** No more than one leading zero byte.
     31 ** Caller supplies dest buffer, and assures that it is long enough,
     32 ** e.g. at least one byte longer that src's buffer.
     33 */
     34 void
     35 DSAU_ConvertUnsignedToSigned(SECItem *dest, SECItem *src)
     36 {
     37    unsigned char *pSrc = src->data;
     38    unsigned char *pDst = dest->data;
     39    unsigned int cntSrc = src->len;
     40 
     41    /* skip any leading zeros. */
     42    while (cntSrc && !(*pSrc)) {
     43        pSrc++;
     44        cntSrc--;
     45    }
     46    if (!cntSrc) {
     47        *pDst = 0;
     48        dest->len = 1;
     49        return;
     50    }
     51 
     52    if (*pSrc & 0x80)
     53        *pDst++ = 0;
     54 
     55    PORT_Memcpy(pDst, pSrc, cntSrc);
     56    dest->len = (pDst - dest->data) + cntSrc;
     57 }
     58 
     59 /*
     60 ** src is a buffer holding a signed variable length integer.
     61 ** dest is a buffer which will be filled with an unsigned integer,
     62 ** MSB first (big endian) with leading zeros, so that the last byte
     63 ** of src will be the LSB of the integer.  The result will be exactly
     64 ** the length specified by the caller in dest->len.
     65 ** src can be shorter than dest.  src can be longer than dst, but only
     66 ** if the extra leading bytes are zeros.
     67 */
     68 SECStatus
     69 DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src)
     70 {
     71    unsigned char *pSrc = src->data;
     72    unsigned char *pDst = dest->data;
     73    unsigned int cntSrc = src->len;
     74    unsigned int cntDst = dest->len;
     75    int zCount = cntDst - cntSrc;
     76 
     77    if (zCount > 0) {
     78        PORT_Memset(pDst, 0, zCount);
     79        PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
     80        return SECSuccess;
     81    }
     82    if (zCount <= 0) {
     83        /* Source is longer than destination.  Check for leading zeros. */
     84        while (zCount++ < 0) {
     85            if (*pSrc++ != 0)
     86                goto loser;
     87        }
     88    }
     89    PORT_Memcpy(pDst, pSrc, cntDst);
     90    return SECSuccess;
     91 
     92 loser:
     93    PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
     94    return SECFailure;
     95 }
     96 
     97 /* src is a "raw" ECDSA or DSA signature, the first half contains r
     98 * and the second half contains s. dest is the DER encoded signature.
     99 */
    100 static SECStatus
    101 common_EncodeDerSig(SECItem *dest, SECItem *src)
    102 {
    103    SECItem *item;
    104    SECItem srcItem;
    105    DSA_ASN1Signature sig;
    106    unsigned char *signedR;
    107    unsigned char *signedS;
    108    unsigned int len;
    109 
    110    /* Allocate memory with room for an extra byte that
    111     * may be required if the top bit in the first byte
    112     * is already set.
    113     */
    114    len = src->len / 2;
    115    signedR = (unsigned char *)PORT_Alloc(len + 1);
    116    if (!signedR)
    117        return SECFailure;
    118    signedS = (unsigned char *)PORT_ZAlloc(len + 1);
    119    if (!signedS) {
    120        if (signedR)
    121            PORT_Free(signedR);
    122        return SECFailure;
    123    }
    124 
    125    PORT_Memset(&sig, 0, sizeof(sig));
    126 
    127    /* Must convert r and s from "unsigned" integers to "signed" integers.
    128    ** If the high order bit of the first byte (MSB) is 1, then must
    129    ** prepend with leading zero.
    130    ** Must remove all but one leading zero byte from numbers.
    131    */
    132    sig.r.type = siUnsignedInteger;
    133    sig.r.data = signedR;
    134    sig.r.len = sizeof signedR;
    135    sig.s.type = siUnsignedInteger;
    136    sig.s.data = signedS;
    137    sig.s.len = sizeof signedR;
    138 
    139    srcItem.data = src->data;
    140    srcItem.len = len;
    141 
    142    DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem);
    143    srcItem.data += len;
    144    DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem);
    145 
    146    item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate);
    147    if (signedR)
    148        PORT_Free(signedR);
    149    if (signedS)
    150        PORT_Free(signedS);
    151    if (item == NULL)
    152        return SECFailure;
    153 
    154    /* XXX leak item? */
    155    return SECSuccess;
    156 }
    157 
    158 /* src is a DER-encoded ECDSA or DSA signature.
    159 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated
    160 ** buffer containing the "raw" signature, which is len bytes of r,
    161 ** followed by len bytes of s. For DSA, len is the length of q.
    162 ** For ECDSA, len depends on the key size used to create the signature.
    163 */
    164 static SECItem *
    165 common_DecodeDerSig(const SECItem *item, unsigned int len)
    166 {
    167    SECItem *result = NULL;
    168    PORTCheapArenaPool arena;
    169    SECStatus status;
    170    DSA_ASN1Signature sig;
    171    SECItem dst;
    172 
    173    PORT_Memset(&sig, 0, sizeof(sig));
    174 
    175    /* Make enough room for r + s. */
    176    PORT_InitCheapArena(&arena, PR_MAX(2 * MAX_ECKEY_LEN, DSA_MAX_SIGNATURE_LEN));
    177 
    178    result = PORT_ZNew(SECItem);
    179    if (result == NULL)
    180        goto loser;
    181 
    182    result->len = 2 * len;
    183    result->data = (unsigned char *)PORT_Alloc(2 * len);
    184    if (result->data == NULL)
    185        goto loser;
    186 
    187    sig.r.type = siUnsignedInteger;
    188    sig.s.type = siUnsignedInteger;
    189    status = SEC_QuickDERDecodeItem(&arena.arena, &sig, DSA_SignatureTemplate, item);
    190    if (status != SECSuccess)
    191        goto loser;
    192 
    193    /* Convert sig.r and sig.s from variable  length signed integers to
    194    ** fixed length unsigned integers.
    195    */
    196    dst.data = result->data;
    197    dst.len = len;
    198    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r);
    199    if (status != SECSuccess)
    200        goto loser;
    201 
    202    dst.data += len;
    203    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s);
    204    if (status != SECSuccess)
    205        goto loser;
    206 
    207 done:
    208    PORT_DestroyCheapArena(&arena);
    209 
    210    return result;
    211 
    212 loser:
    213    if (result != NULL) {
    214        SECITEM_FreeItem(result, PR_TRUE);
    215        result = NULL;
    216    }
    217    goto done;
    218 }
    219 
    220 /* src is a "raw" DSA1 signature, 20 bytes of r followed by 20 bytes of s.
    221 ** dest is the signature DER encoded. ?
    222 */
    223 SECStatus
    224 DSAU_EncodeDerSig(SECItem *dest, SECItem *src)
    225 {
    226    PORT_Assert(src->len == 2 * DSA1_SUBPRIME_LEN);
    227    if (src->len != 2 * DSA1_SUBPRIME_LEN) {
    228        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
    229        return SECFailure;
    230    }
    231 
    232    return common_EncodeDerSig(dest, src);
    233 }
    234 
    235 /* src is a "raw" DSA signature of length len (len/2 bytes of r followed
    236 ** by len/2 bytes of s). dest is the signature DER encoded.
    237 */
    238 SECStatus
    239 DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, unsigned int len)
    240 {
    241 
    242    PORT_Assert((src->len == len) && (len % 2 == 0));
    243    if ((src->len != len) || (src->len % 2 != 0)) {
    244        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
    245        return SECFailure;
    246    }
    247 
    248    return common_EncodeDerSig(dest, src);
    249 }
    250 
    251 /* src is a DER-encoded DSA signature.
    252 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated
    253 ** buffer containing the "raw" DSA1 signature, which is 20 bytes of r,
    254 ** followed by 20 bytes of s.
    255 */
    256 SECItem *
    257 DSAU_DecodeDerSig(const SECItem *item)
    258 {
    259    return common_DecodeDerSig(item, DSA1_SUBPRIME_LEN);
    260 }
    261 
    262 /* src is a DER-encoded ECDSA signature.
    263 ** Returns a newly-allocated SECItem structure, pointing at a newly allocated
    264 ** buffer containing the "raw" ECDSA signature of length len containing
    265 ** r followed by s (both padded to take up exactly len/2 bytes).
    266 */
    267 SECItem *
    268 DSAU_DecodeDerSigToLen(const SECItem *item, unsigned int len)
    269 {
    270    return common_DecodeDerSig(item, len / 2);
    271 }