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