quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

asn1write.c (12571B)


      1 /*
      2  * ASN.1 buffer writing functionality
      3  *
      4  *  Copyright The Mbed TLS Contributors
      5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
      6  */
      7 
      8 #include "common.h"
      9 
     10 #if defined(MBEDTLS_ASN1_WRITE_C) || defined(MBEDTLS_X509_USE_C) || \
     11     defined(MBEDTLS_PSA_UTIL_HAVE_ECDSA)
     12 
     13 #include "mbedtls/asn1write.h"
     14 #include "mbedtls/error.h"
     15 
     16 #include <string.h>
     17 
     18 #include "mbedtls/platform.h"
     19 
     20 #if defined(MBEDTLS_ASN1_PARSE_C)
     21 #include "mbedtls/asn1.h"
     22 #endif
     23 
     24 int mbedtls_asn1_write_len(unsigned char **p, const unsigned char *start, size_t len)
     25 {
     26 #if SIZE_MAX > 0xFFFFFFFF
     27     if (len > 0xFFFFFFFF) {
     28         return MBEDTLS_ERR_ASN1_INVALID_LENGTH;
     29     }
     30 #endif
     31 
     32     int required = 1;
     33 
     34     if (len >= 0x80) {
     35         for (size_t l = len; l != 0; l >>= 8) {
     36             required++;
     37         }
     38     }
     39 
     40     if (required > (*p - start)) {
     41         return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
     42     }
     43 
     44     do {
     45         *--(*p) = MBEDTLS_BYTE_0(len);
     46         len >>= 8;
     47     } while (len);
     48 
     49     if (required > 1) {
     50         *--(*p) = (unsigned char) (0x80 + required - 1);
     51     }
     52 
     53     return required;
     54 }
     55 
     56 int mbedtls_asn1_write_tag(unsigned char **p, const unsigned char *start, unsigned char tag)
     57 {
     58     if (*p - start < 1) {
     59         return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
     60     }
     61 
     62     *--(*p) = tag;
     63 
     64     return 1;
     65 }
     66 #endif /* MBEDTLS_ASN1_WRITE_C || MBEDTLS_X509_USE_C || MBEDTLS_PSA_UTIL_HAVE_ECDSA */
     67 
     68 #if defined(MBEDTLS_ASN1_WRITE_C)
     69 static int mbedtls_asn1_write_len_and_tag(unsigned char **p,
     70                                           const unsigned char *start,
     71                                           size_t len,
     72                                           unsigned char tag)
     73 {
     74     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     75 
     76     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
     77     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, tag));
     78 
     79     return (int) len;
     80 }
     81 
     82 int mbedtls_asn1_write_raw_buffer(unsigned char **p, const unsigned char *start,
     83                                   const unsigned char *buf, size_t size)
     84 {
     85     size_t len = 0;
     86 
     87     if (*p < start || (size_t) (*p - start) < size) {
     88         return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
     89     }
     90 
     91     len = size;
     92     (*p) -= len;
     93     if (len != 0) {
     94         memcpy(*p, buf, len);
     95     }
     96 
     97     return (int) len;
     98 }
     99 
    100 #if defined(MBEDTLS_BIGNUM_C)
    101 int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start, const mbedtls_mpi *X)
    102 {
    103     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    104     size_t len = 0;
    105 
    106     // Write the MPI
    107     //
    108     len = mbedtls_mpi_size(X);
    109 
    110     /* DER represents 0 with a sign bit (0=nonnegative) and 7 value bits, not
    111      * as 0 digits. We need to end up with 020100, not with 0200. */
    112     if (len == 0) {
    113         len = 1;
    114     }
    115 
    116     if (*p < start || (size_t) (*p - start) < len) {
    117         return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
    118     }
    119 
    120     (*p) -= len;
    121     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(X, *p, len));
    122 
    123     // DER format assumes 2s complement for numbers, so the leftmost bit
    124     // should be 0 for positive numbers and 1 for negative numbers.
    125     //
    126     if (X->s == 1 && **p & 0x80) {
    127         if (*p - start < 1) {
    128             return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
    129         }
    130 
    131         *--(*p) = 0x00;
    132         len += 1;
    133     }
    134 
    135     ret = mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_INTEGER);
    136 
    137 cleanup:
    138     return ret;
    139 }
    140 #endif /* MBEDTLS_BIGNUM_C */
    141 
    142 int mbedtls_asn1_write_null(unsigned char **p, const unsigned char *start)
    143 {
    144     // Write NULL
    145     //
    146     return mbedtls_asn1_write_len_and_tag(p, start, 0, MBEDTLS_ASN1_NULL);
    147 }
    148 
    149 int mbedtls_asn1_write_oid(unsigned char **p, const unsigned char *start,
    150                            const char *oid, size_t oid_len)
    151 {
    152     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    153     size_t len = 0;
    154 
    155     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start,
    156                                                             (const unsigned char *) oid, oid_len));
    157     return mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_OID);
    158 }
    159 
    160 int mbedtls_asn1_write_algorithm_identifier(unsigned char **p, const unsigned char *start,
    161                                             const char *oid, size_t oid_len,
    162                                             size_t par_len)
    163 {
    164     return mbedtls_asn1_write_algorithm_identifier_ext(p, start, oid, oid_len, par_len, 1);
    165 }
    166 
    167 int mbedtls_asn1_write_algorithm_identifier_ext(unsigned char **p, const unsigned char *start,
    168                                                 const char *oid, size_t oid_len,
    169                                                 size_t par_len, int has_par)
    170 {
    171     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    172     size_t len = 0;
    173 
    174     if (has_par) {
    175         if (par_len == 0) {
    176             MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_null(p, start));
    177         } else {
    178             len += par_len;
    179         }
    180     }
    181 
    182     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, oid_len));
    183 
    184     return mbedtls_asn1_write_len_and_tag(p, start, len,
    185                                           MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
    186 }
    187 
    188 int mbedtls_asn1_write_bool(unsigned char **p, const unsigned char *start, int boolean)
    189 {
    190     size_t len = 0;
    191 
    192     if (*p - start < 1) {
    193         return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
    194     }
    195 
    196     *--(*p) = (boolean) ? 255 : 0;
    197     len++;
    198 
    199     return mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_BOOLEAN);
    200 }
    201 
    202 static int asn1_write_tagged_int(unsigned char **p, const unsigned char *start, int val, int tag)
    203 {
    204     size_t len = 0;
    205 
    206     do {
    207         if (*p - start < 1) {
    208             return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
    209         }
    210         len += 1;
    211         *--(*p) = val & 0xff;
    212         val >>= 8;
    213     } while (val > 0);
    214 
    215     if (**p & 0x80) {
    216         if (*p - start < 1) {
    217             return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
    218         }
    219         *--(*p) = 0x00;
    220         len += 1;
    221     }
    222 
    223     return mbedtls_asn1_write_len_and_tag(p, start, len, tag);
    224 }
    225 
    226 int mbedtls_asn1_write_int(unsigned char **p, const unsigned char *start, int val)
    227 {
    228     return asn1_write_tagged_int(p, start, val, MBEDTLS_ASN1_INTEGER);
    229 }
    230 
    231 int mbedtls_asn1_write_enum(unsigned char **p, const unsigned char *start, int val)
    232 {
    233     return asn1_write_tagged_int(p, start, val, MBEDTLS_ASN1_ENUMERATED);
    234 }
    235 
    236 int mbedtls_asn1_write_tagged_string(unsigned char **p, const unsigned char *start, int tag,
    237                                      const char *text, size_t text_len)
    238 {
    239     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    240     size_t len = 0;
    241 
    242     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start,
    243                                                             (const unsigned char *) text,
    244                                                             text_len));
    245 
    246     return mbedtls_asn1_write_len_and_tag(p, start, len, tag);
    247 }
    248 
    249 int mbedtls_asn1_write_utf8_string(unsigned char **p, const unsigned char *start,
    250                                    const char *text, size_t text_len)
    251 {
    252     return mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len);
    253 }
    254 
    255 int mbedtls_asn1_write_printable_string(unsigned char **p, const unsigned char *start,
    256                                         const char *text, size_t text_len)
    257 {
    258     return mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text,
    259                                             text_len);
    260 }
    261 
    262 int mbedtls_asn1_write_ia5_string(unsigned char **p, const unsigned char *start,
    263                                   const char *text, size_t text_len)
    264 {
    265     return mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len);
    266 }
    267 
    268 int mbedtls_asn1_write_named_bitstring(unsigned char **p,
    269                                        const unsigned char *start,
    270                                        const unsigned char *buf,
    271                                        size_t bits)
    272 {
    273     size_t unused_bits, byte_len;
    274     const unsigned char *cur_byte;
    275     unsigned char cur_byte_shifted;
    276     unsigned char bit;
    277 
    278     byte_len = (bits + 7) / 8;
    279     unused_bits = (byte_len * 8) - bits;
    280 
    281     /*
    282      * Named bitstrings require that trailing 0s are excluded in the encoding
    283      * of the bitstring. Trailing 0s are considered part of the 'unused' bits
    284      * when encoding this value in the first content octet
    285      */
    286     if (bits != 0) {
    287         cur_byte = buf + byte_len - 1;
    288         cur_byte_shifted = *cur_byte >> unused_bits;
    289 
    290         for (;;) {
    291             bit = cur_byte_shifted & 0x1;
    292             cur_byte_shifted >>= 1;
    293 
    294             if (bit != 0) {
    295                 break;
    296             }
    297 
    298             bits--;
    299             if (bits == 0) {
    300                 break;
    301             }
    302 
    303             if (bits % 8 == 0) {
    304                 cur_byte_shifted = *--cur_byte;
    305             }
    306         }
    307     }
    308 
    309     return mbedtls_asn1_write_bitstring(p, start, buf, bits);
    310 }
    311 
    312 int mbedtls_asn1_write_bitstring(unsigned char **p, const unsigned char *start,
    313                                  const unsigned char *buf, size_t bits)
    314 {
    315     size_t len = 0;
    316     size_t unused_bits, byte_len;
    317 
    318     byte_len = (bits + 7) / 8;
    319     unused_bits = (byte_len * 8) - bits;
    320 
    321     if (*p < start || (size_t) (*p - start) < byte_len + 1) {
    322         return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
    323     }
    324 
    325     len = byte_len + 1;
    326 
    327     /* Write the bitstring. Ensure the unused bits are zeroed */
    328     if (byte_len > 0) {
    329         byte_len--;
    330         *--(*p) = buf[byte_len] & ~((0x1 << unused_bits) - 1);
    331         (*p) -= byte_len;
    332         memcpy(*p, buf, byte_len);
    333     }
    334 
    335     /* Write unused bits */
    336     *--(*p) = (unsigned char) unused_bits;
    337 
    338     return mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_BIT_STRING);
    339 }
    340 
    341 int mbedtls_asn1_write_octet_string(unsigned char **p, const unsigned char *start,
    342                                     const unsigned char *buf, size_t size)
    343 {
    344     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    345     size_t len = 0;
    346 
    347     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start, buf, size));
    348 
    349     return mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_OCTET_STRING);
    350 }
    351 
    352 
    353 #if !defined(MBEDTLS_ASN1_PARSE_C)
    354 /* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(),
    355  * which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */
    356 static mbedtls_asn1_named_data *asn1_find_named_data(
    357     mbedtls_asn1_named_data *list,
    358     const char *oid, size_t len)
    359 {
    360     while (list != NULL) {
    361         if (list->oid.len == len &&
    362             memcmp(list->oid.p, oid, len) == 0) {
    363             break;
    364         }
    365 
    366         list = list->next;
    367     }
    368 
    369     return list;
    370 }
    371 #else
    372 #define asn1_find_named_data(list, oid, len) \
    373     ((mbedtls_asn1_named_data *) mbedtls_asn1_find_named_data(list, oid, len))
    374 #endif
    375 
    376 mbedtls_asn1_named_data *mbedtls_asn1_store_named_data(
    377     mbedtls_asn1_named_data **head,
    378     const char *oid, size_t oid_len,
    379     const unsigned char *val,
    380     size_t val_len)
    381 {
    382     mbedtls_asn1_named_data *cur;
    383 
    384     if ((cur = asn1_find_named_data(*head, oid, oid_len)) == NULL) {
    385         // Add new entry if not present yet based on OID
    386         //
    387         cur = (mbedtls_asn1_named_data *) mbedtls_calloc(1,
    388                                                          sizeof(mbedtls_asn1_named_data));
    389         if (cur == NULL) {
    390             return NULL;
    391         }
    392 
    393         cur->oid.len = oid_len;
    394         cur->oid.p = mbedtls_calloc(1, oid_len);
    395         if (cur->oid.p == NULL) {
    396             mbedtls_free(cur);
    397             return NULL;
    398         }
    399 
    400         memcpy(cur->oid.p, oid, oid_len);
    401 
    402         cur->val.len = val_len;
    403         if (val_len != 0) {
    404             cur->val.p = mbedtls_calloc(1, val_len);
    405             if (cur->val.p == NULL) {
    406                 mbedtls_free(cur->oid.p);
    407                 mbedtls_free(cur);
    408                 return NULL;
    409             }
    410         }
    411 
    412         cur->next = *head;
    413         *head = cur;
    414     } else if (val_len == 0) {
    415         mbedtls_free(cur->val.p);
    416         cur->val.p = NULL;
    417         cur->val.len = 0;
    418     } else if (cur->val.len != val_len) {
    419         /*
    420          * Enlarge existing value buffer if needed
    421          * Preserve old data until the allocation succeeded, to leave list in
    422          * a consistent state in case allocation fails.
    423          */
    424         void *p = mbedtls_calloc(1, val_len);
    425         if (p == NULL) {
    426             return NULL;
    427         }
    428 
    429         mbedtls_free(cur->val.p);
    430         cur->val.p = p;
    431         cur->val.len = val_len;
    432     }
    433 
    434     if (val != NULL && val_len != 0) {
    435         memcpy(cur->val.p, val, val_len);
    436     }
    437 
    438     return cur;
    439 }
    440 #endif /* MBEDTLS_ASN1_WRITE_C */