/src/openssl30/crypto/asn1/a_mbstr.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* | 
| 2 |  |  * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. | 
| 3 |  |  * | 
| 4 |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | 
| 5 |  |  * this file except in compliance with the License.  You can obtain a copy | 
| 6 |  |  * in the file LICENSE in the source distribution or at | 
| 7 |  |  * https://www.openssl.org/source/license.html | 
| 8 |  |  */ | 
| 9 |  |  | 
| 10 |  | #include <stdio.h> | 
| 11 |  | #include "crypto/ctype.h" | 
| 12 |  | #include "internal/cryptlib.h" | 
| 13 |  | #include "internal/unicode.h" | 
| 14 |  | #include <openssl/asn1.h> | 
| 15 |  |  | 
| 16 |  | static int traverse_string(const unsigned char *p, int len, int inform, | 
| 17 |  |                            int (*rfunc) (unsigned long value, void *in), | 
| 18 |  |                            void *arg); | 
| 19 |  | static int in_utf8(unsigned long value, void *arg); | 
| 20 |  | static int out_utf8(unsigned long value, void *arg); | 
| 21 |  | static int type_str(unsigned long value, void *arg); | 
| 22 |  | static int cpy_asc(unsigned long value, void *arg); | 
| 23 |  | static int cpy_bmp(unsigned long value, void *arg); | 
| 24 |  | static int cpy_univ(unsigned long value, void *arg); | 
| 25 |  | static int cpy_utf8(unsigned long value, void *arg); | 
| 26 |  |  | 
| 27 |  | /* | 
| 28 |  |  * These functions take a string in UTF8, ASCII or multibyte form and a mask | 
| 29 |  |  * of permissible ASN1 string types. It then works out the minimal type | 
| 30 |  |  * (using the order Numeric < Printable < IA5 < T61 < BMP < Universal < UTF8) | 
| 31 |  |  * and creates a string of the correct type with the supplied data. Yes this is | 
| 32 |  |  * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum | 
| 33 |  |  * size limits too. | 
| 34 |  |  */ | 
| 35 |  |  | 
| 36 |  | int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, | 
| 37 |  |                        int inform, unsigned long mask) | 
| 38 | 5.07M | { | 
| 39 | 5.07M |     return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0); | 
| 40 | 5.07M | } | 
| 41 |  |  | 
| 42 |  | int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, | 
| 43 |  |                         int inform, unsigned long mask, | 
| 44 |  |                         long minsize, long maxsize) | 
| 45 | 2.25M | { | 
| 46 | 2.25M |     int str_type; | 
| 47 | 2.25M |     int ret; | 
| 48 | 2.25M |     char free_out; | 
| 49 | 2.25M |     int outform, outlen = 0; | 
| 50 | 2.25M |     ASN1_STRING *dest; | 
| 51 | 2.25M |     unsigned char *p; | 
| 52 | 2.25M |     int nchar; | 
| 53 | 2.25M |     int (*cpyfunc) (unsigned long, void *) = NULL; | 
| 54 | 2.25M |     if (len == -1) | 
| 55 | 0 |         len = strlen((const char *)in); | 
| 56 | 2.25M |     if (!mask) | 
| 57 | 0 |         mask = DIRSTRING_TYPE; | 
| 58 | 2.25M |     if (len < 0) | 
| 59 | 0 |         return -1; | 
| 60 |  |  | 
| 61 |  |     /* First do a string check and work out the number of characters */ | 
| 62 | 2.25M |     switch (inform) { | 
| 63 |  |  | 
| 64 | 817k |     case MBSTRING_BMP: | 
| 65 | 817k |         if (len & 1) { | 
| 66 | 0 |             ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH); | 
| 67 | 0 |             return -1; | 
| 68 | 0 |         } | 
| 69 | 817k |         nchar = len >> 1; | 
| 70 | 817k |         break; | 
| 71 |  |  | 
| 72 | 304k |     case MBSTRING_UNIV: | 
| 73 | 304k |         if (len & 3) { | 
| 74 | 0 |             ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); | 
| 75 | 0 |             return -1; | 
| 76 | 0 |         } | 
| 77 | 304k |         nchar = len >> 2; | 
| 78 | 304k |         break; | 
| 79 |  |  | 
| 80 | 315k |     case MBSTRING_UTF8: | 
| 81 | 315k |         nchar = 0; | 
| 82 |  |         /* This counts the characters and does utf8 syntax checking */ | 
| 83 | 315k |         ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); | 
| 84 | 315k |         if (ret < 0) { | 
| 85 | 21.4k |             ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING); | 
| 86 | 21.4k |             return -1; | 
| 87 | 21.4k |         } | 
| 88 | 293k |         break; | 
| 89 |  |  | 
| 90 | 820k |     case MBSTRING_ASC: | 
| 91 | 820k |         nchar = len; | 
| 92 | 820k |         break; | 
| 93 |  |  | 
| 94 | 0 |     default: | 
| 95 | 0 |         ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT); | 
| 96 | 0 |         return -1; | 
| 97 | 2.25M |     } | 
| 98 |  |  | 
| 99 | 2.23M |     if ((minsize > 0) && (nchar < minsize)) { | 
| 100 | 0 |         ERR_raise_data(ERR_LIB_ASN1, ASN1_R_STRING_TOO_SHORT, | 
| 101 | 0 |                        "minsize=%ld", minsize); | 
| 102 | 0 |         return -1; | 
| 103 | 0 |     } | 
| 104 |  |  | 
| 105 | 2.23M |     if ((maxsize > 0) && (nchar > maxsize)) { | 
| 106 | 0 |         ERR_raise_data(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG, | 
| 107 | 0 |                        "maxsize=%ld", maxsize); | 
| 108 | 0 |         return -1; | 
| 109 | 0 |     } | 
| 110 |  |  | 
| 111 |  |     /* Now work out minimal type (if any) */ | 
| 112 | 2.23M |     if (traverse_string(in, len, inform, type_str, &mask) < 0) { | 
| 113 | 1.01k |         ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_CHARACTERS); | 
| 114 | 1.01k |         return -1; | 
| 115 | 1.01k |     } | 
| 116 |  |  | 
| 117 |  |     /* Now work out output format and string type */ | 
| 118 | 2.23M |     outform = MBSTRING_ASC; | 
| 119 | 2.23M |     if (mask & B_ASN1_NUMERICSTRING) | 
| 120 | 0 |         str_type = V_ASN1_NUMERICSTRING; | 
| 121 | 2.23M |     else if (mask & B_ASN1_PRINTABLESTRING) | 
| 122 | 0 |         str_type = V_ASN1_PRINTABLESTRING; | 
| 123 | 2.23M |     else if (mask & B_ASN1_IA5STRING) | 
| 124 | 0 |         str_type = V_ASN1_IA5STRING; | 
| 125 | 2.23M |     else if (mask & B_ASN1_T61STRING) | 
| 126 | 0 |         str_type = V_ASN1_T61STRING; | 
| 127 | 2.23M |     else if (mask & B_ASN1_BMPSTRING) { | 
| 128 | 0 |         str_type = V_ASN1_BMPSTRING; | 
| 129 | 0 |         outform = MBSTRING_BMP; | 
| 130 | 2.23M |     } else if (mask & B_ASN1_UNIVERSALSTRING) { | 
| 131 | 0 |         str_type = V_ASN1_UNIVERSALSTRING; | 
| 132 | 0 |         outform = MBSTRING_UNIV; | 
| 133 | 2.23M |     } else { | 
| 134 | 2.23M |         str_type = V_ASN1_UTF8STRING; | 
| 135 | 2.23M |         outform = MBSTRING_UTF8; | 
| 136 | 2.23M |     } | 
| 137 | 2.23M |     if (!out) | 
| 138 | 0 |         return str_type; | 
| 139 | 2.23M |     if (*out) { | 
| 140 | 2.23M |         free_out = 0; | 
| 141 | 2.23M |         dest = *out; | 
| 142 | 2.23M |         OPENSSL_free(dest->data); | 
| 143 | 2.23M |         dest->data = NULL; | 
| 144 | 2.23M |         dest->length = 0; | 
| 145 | 2.23M |         dest->type = str_type; | 
| 146 | 2.23M |     } else { | 
| 147 | 0 |         free_out = 1; | 
| 148 | 0 |         dest = ASN1_STRING_type_new(str_type); | 
| 149 | 0 |         if (dest == NULL) { | 
| 150 | 0 |             ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); | 
| 151 | 0 |             return -1; | 
| 152 | 0 |         } | 
| 153 | 0 |         *out = dest; | 
| 154 | 0 |     } | 
| 155 |  |     /* If both the same type just copy across */ | 
| 156 | 2.23M |     if (inform == outform) { | 
| 157 | 293k |         if (!ASN1_STRING_set(dest, in, len)) { | 
| 158 | 0 |             ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); | 
| 159 | 0 |             return -1; | 
| 160 | 0 |         } | 
| 161 | 293k |         return str_type; | 
| 162 | 293k |     } | 
| 163 |  |  | 
| 164 |  |     /* Work out how much space the destination will need */ | 
| 165 | 1.94M |     switch (outform) { | 
| 166 | 0 |     case MBSTRING_ASC: | 
| 167 | 0 |         outlen = nchar; | 
| 168 | 0 |         cpyfunc = cpy_asc; | 
| 169 | 0 |         break; | 
| 170 |  |  | 
| 171 | 0 |     case MBSTRING_BMP: | 
| 172 | 0 |         outlen = nchar << 1; | 
| 173 | 0 |         cpyfunc = cpy_bmp; | 
| 174 | 0 |         break; | 
| 175 |  |  | 
| 176 | 0 |     case MBSTRING_UNIV: | 
| 177 | 0 |         outlen = nchar << 2; | 
| 178 | 0 |         cpyfunc = cpy_univ; | 
| 179 | 0 |         break; | 
| 180 |  |  | 
| 181 | 1.94M |     case MBSTRING_UTF8: | 
| 182 | 1.94M |         outlen = 0; | 
| 183 | 1.94M |         traverse_string(in, len, inform, out_utf8, &outlen); | 
| 184 | 1.94M |         cpyfunc = cpy_utf8; | 
| 185 | 1.94M |         break; | 
| 186 | 1.94M |     } | 
| 187 | 1.94M |     if ((p = OPENSSL_malloc(outlen + 1)) == NULL) { | 
| 188 | 0 |         if (free_out) | 
| 189 | 0 |             ASN1_STRING_free(dest); | 
| 190 | 0 |         ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); | 
| 191 | 0 |         return -1; | 
| 192 | 0 |     } | 
| 193 | 1.94M |     dest->length = outlen; | 
| 194 | 1.94M |     dest->data = p; | 
| 195 | 1.94M |     p[outlen] = 0; | 
| 196 | 1.94M |     traverse_string(in, len, inform, cpyfunc, &p); | 
| 197 | 1.94M |     return str_type; | 
| 198 | 1.94M | } | 
| 199 |  |  | 
| 200 |  | /* | 
| 201 |  |  * This function traverses a string and passes the value of each character to | 
| 202 |  |  * an optional function along with a void * argument. | 
| 203 |  |  */ | 
| 204 |  |  | 
| 205 |  | static int traverse_string(const unsigned char *p, int len, int inform, | 
| 206 |  |                            int (*rfunc) (unsigned long value, void *in), | 
| 207 |  |                            void *arg) | 
| 208 | 14.7M | { | 
| 209 | 14.7M |     unsigned long value; | 
| 210 | 14.7M |     int ret; | 
| 211 | 429M |     while (len) { | 
| 212 | 415M |         if (inform == MBSTRING_ASC) { | 
| 213 | 391M |             value = *p++; | 
| 214 | 391M |             len--; | 
| 215 | 391M |         } else if (inform == MBSTRING_BMP) { | 
| 216 | 3.53M |             value = *p++ << 8; | 
| 217 | 3.53M |             value |= *p++; | 
| 218 | 3.53M |             len -= 2; | 
| 219 | 20.1M |         } else if (inform == MBSTRING_UNIV) { | 
| 220 | 15.9M |             value = ((unsigned long)*p++) << 24; | 
| 221 | 15.9M |             value |= ((unsigned long)*p++) << 16; | 
| 222 | 15.9M |             value |= *p++ << 8; | 
| 223 | 15.9M |             value |= *p++; | 
| 224 | 15.9M |             len -= 4; | 
| 225 | 15.9M |         } else { | 
| 226 | 4.19M |             ret = UTF8_getc(p, len, &value); | 
| 227 | 4.19M |             if (ret < 0) | 
| 228 | 33.2k |                 return -1; | 
| 229 | 4.16M |             len -= ret; | 
| 230 | 4.16M |             p += ret; | 
| 231 | 4.16M |         } | 
| 232 | 415M |         if (rfunc) { | 
| 233 | 415M |             ret = rfunc(value, arg); | 
| 234 | 415M |             if (ret <= 0) | 
| 235 | 1.12k |                 return ret; | 
| 236 | 415M |         } | 
| 237 | 415M |     } | 
| 238 | 14.6M |     return 1; | 
| 239 | 14.7M | } | 
| 240 |  |  | 
| 241 |  | /* Various utility functions for traverse_string */ | 
| 242 |  |  | 
| 243 |  | /* Just count number of characters */ | 
| 244 |  |  | 
| 245 |  | static int in_utf8(unsigned long value, void *arg) | 
| 246 | 1.85M | { | 
| 247 | 1.85M |     int *nchar; | 
| 248 |  |  | 
| 249 | 1.85M |     if (!is_unicode_valid(value)) | 
| 250 | 108 |         return -2; | 
| 251 | 1.85M |     nchar = arg; | 
| 252 | 1.85M |     (*nchar)++; | 
| 253 | 1.85M |     return 1; | 
| 254 | 1.85M | } | 
| 255 |  |  | 
| 256 |  | /* Determine size of output as a UTF8 String */ | 
| 257 |  |  | 
| 258 |  | static int out_utf8(unsigned long value, void *arg) | 
| 259 | 113M | { | 
| 260 | 113M |     int *outlen, len; | 
| 261 |  |  | 
| 262 | 113M |     len = UTF8_putc(NULL, -1, value); | 
| 263 | 113M |     if (len <= 0) | 
| 264 | 0 |         return len; | 
| 265 | 113M |     outlen = arg; | 
| 266 | 113M |     *outlen += len; | 
| 267 | 113M |     return 1; | 
| 268 | 113M | } | 
| 269 |  |  | 
| 270 |  | /* | 
| 271 |  |  * Determine the "type" of a string: check each character against a supplied | 
| 272 |  |  * "mask". | 
| 273 |  |  */ | 
| 274 |  |  | 
| 275 |  | static int type_str(unsigned long value, void *arg) | 
| 276 | 115M | { | 
| 277 | 115M |     unsigned long types = *((unsigned long *)arg); | 
| 278 | 115M |     const int native = value > INT_MAX ? INT_MAX : ossl_fromascii(value); | 
| 279 |  |  | 
| 280 | 115M |     if ((types & B_ASN1_NUMERICSTRING) && !(ossl_isdigit(native) | 
| 281 | 0 |                                             || native == ' ')) | 
| 282 | 0 |         types &= ~B_ASN1_NUMERICSTRING; | 
| 283 | 115M |     if ((types & B_ASN1_PRINTABLESTRING) && !ossl_isasn1print(native)) | 
| 284 | 0 |         types &= ~B_ASN1_PRINTABLESTRING; | 
| 285 | 115M |     if ((types & B_ASN1_IA5STRING) && !ossl_isascii(native)) | 
| 286 | 0 |         types &= ~B_ASN1_IA5STRING; | 
| 287 | 115M |     if ((types & B_ASN1_T61STRING) && (value > 0xff)) | 
| 288 | 0 |         types &= ~B_ASN1_T61STRING; | 
| 289 | 115M |     if ((types & B_ASN1_BMPSTRING) && (value > 0xffff)) | 
| 290 | 0 |         types &= ~B_ASN1_BMPSTRING; | 
| 291 | 115M |     if ((types & B_ASN1_UTF8STRING) && !is_unicode_valid(value)) | 
| 292 | 1.01k |         types &= ~B_ASN1_UTF8STRING; | 
| 293 | 115M |     if (!types) | 
| 294 | 1.01k |         return -1; | 
| 295 | 115M |     *((unsigned long *)arg) = types; | 
| 296 | 115M |     return 1; | 
| 297 | 115M | } | 
| 298 |  |  | 
| 299 |  | /* Copy one byte per character ASCII like strings */ | 
| 300 |  |  | 
| 301 |  | static int cpy_asc(unsigned long value, void *arg) | 
| 302 | 0 | { | 
| 303 | 0 |     unsigned char **p, *q; | 
| 304 | 0 |     p = arg; | 
| 305 | 0 |     q = *p; | 
| 306 | 0 |     *q = (unsigned char)value; | 
| 307 | 0 |     (*p)++; | 
| 308 | 0 |     return 1; | 
| 309 | 0 | } | 
| 310 |  |  | 
| 311 |  | /* Copy two byte per character BMPStrings */ | 
| 312 |  |  | 
| 313 |  | static int cpy_bmp(unsigned long value, void *arg) | 
| 314 | 0 | { | 
| 315 | 0 |     unsigned char **p, *q; | 
| 316 | 0 |     p = arg; | 
| 317 | 0 |     q = *p; | 
| 318 | 0 |     *q++ = (unsigned char)((value >> 8) & 0xff); | 
| 319 | 0 |     *q = (unsigned char)(value & 0xff); | 
| 320 | 0 |     *p += 2; | 
| 321 | 0 |     return 1; | 
| 322 | 0 | } | 
| 323 |  |  | 
| 324 |  | /* Copy four byte per character UniversalStrings */ | 
| 325 |  |  | 
| 326 |  | static int cpy_univ(unsigned long value, void *arg) | 
| 327 | 0 | { | 
| 328 | 0 |     unsigned char **p, *q; | 
| 329 | 0 |     p = arg; | 
| 330 | 0 |     q = *p; | 
| 331 | 0 |     *q++ = (unsigned char)((value >> 24) & 0xff); | 
| 332 | 0 |     *q++ = (unsigned char)((value >> 16) & 0xff); | 
| 333 | 0 |     *q++ = (unsigned char)((value >> 8) & 0xff); | 
| 334 | 0 |     *q = (unsigned char)(value & 0xff); | 
| 335 | 0 |     *p += 4; | 
| 336 | 0 |     return 1; | 
| 337 | 0 | } | 
| 338 |  |  | 
| 339 |  | /* Copy to a UTF8String */ | 
| 340 |  |  | 
| 341 |  | static int cpy_utf8(unsigned long value, void *arg) | 
| 342 | 137M | { | 
| 343 | 137M |     unsigned char **p; | 
| 344 | 137M |     int ret; | 
| 345 | 137M |     p = arg; | 
| 346 |  |     /* We already know there is enough room so pass 0xff as the length */ | 
| 347 | 137M |     ret = UTF8_putc(*p, 0xff, value); | 
| 348 | 137M |     *p += ret; | 
| 349 | 137M |     return 1; | 
| 350 | 137M | } |