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