2 * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
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
11 #include "crypto/ctype.h"
12 #include "internal/cryptlib.h"
13 #include "internal/unicode.h"
14 #include <openssl/asn1.h>
16 static int traverse_string(const unsigned char *p
, int len
, int inform
,
17 int (*rfunc
) (unsigned long value
, void *in
),
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
);
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
36 int ASN1_mbstring_copy(ASN1_STRING
**out
, const unsigned char *in
, int len
,
37 int inform
, unsigned long mask
)
39 return ASN1_mbstring_ncopy(out
, in
, len
, inform
, mask
, 0, 0);
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
)
49 int outform
, outlen
= 0;
53 int (*cpyfunc
) (unsigned long, void *) = NULL
;
55 len
= strlen((const char *)in
);
57 mask
= DIRSTRING_TYPE
;
61 /* First do a string check and work out the number of characters */
66 ERR_raise(ERR_LIB_ASN1
, ASN1_R_INVALID_BMPSTRING_LENGTH
);
74 ERR_raise(ERR_LIB_ASN1
, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH
);
82 /* This counts the characters and does utf8 syntax checking */
83 ret
= traverse_string(in
, len
, MBSTRING_UTF8
, in_utf8
, &nchar
);
85 ERR_raise(ERR_LIB_ASN1
, ASN1_R_INVALID_UTF8STRING
);
95 ERR_raise(ERR_LIB_ASN1
, ASN1_R_UNKNOWN_FORMAT
);
99 if ((minsize
> 0) && (nchar
< minsize
)) {
100 ERR_raise_data(ERR_LIB_ASN1
, ASN1_R_STRING_TOO_SHORT
,
101 "minsize=%ld", minsize
);
105 if ((maxsize
> 0) && (nchar
> maxsize
)) {
106 ERR_raise_data(ERR_LIB_ASN1
, ASN1_R_STRING_TOO_LONG
,
107 "maxsize=%ld", maxsize
);
111 /* Now work out minimal type (if any) */
112 if (traverse_string(in
, len
, inform
, type_str
, &mask
) < 0) {
113 ERR_raise(ERR_LIB_ASN1
, ASN1_R_ILLEGAL_CHARACTERS
);
117 /* Now work out output format and string type */
118 outform
= MBSTRING_ASC
;
119 if (mask
& B_ASN1_NUMERICSTRING
)
120 str_type
= V_ASN1_NUMERICSTRING
;
121 else if (mask
& B_ASN1_PRINTABLESTRING
)
122 str_type
= V_ASN1_PRINTABLESTRING
;
123 else if (mask
& B_ASN1_IA5STRING
)
124 str_type
= V_ASN1_IA5STRING
;
125 else if (mask
& B_ASN1_T61STRING
)
126 str_type
= V_ASN1_T61STRING
;
127 else if (mask
& B_ASN1_BMPSTRING
) {
128 str_type
= V_ASN1_BMPSTRING
;
129 outform
= MBSTRING_BMP
;
130 } else if (mask
& B_ASN1_UNIVERSALSTRING
) {
131 str_type
= V_ASN1_UNIVERSALSTRING
;
132 outform
= MBSTRING_UNIV
;
134 str_type
= V_ASN1_UTF8STRING
;
135 outform
= MBSTRING_UTF8
;
142 ASN1_STRING_set0(dest
, NULL
, 0);
143 dest
->type
= str_type
;
146 dest
= ASN1_STRING_type_new(str_type
);
148 ERR_raise(ERR_LIB_ASN1
, ERR_R_ASN1_LIB
);
153 /* If both the same type just copy across */
154 if (inform
== outform
) {
155 if (!ASN1_STRING_set(dest
, in
, len
)) {
156 ERR_raise(ERR_LIB_ASN1
, ERR_R_ASN1_LIB
);
162 /* Work out how much space the destination will need */
181 traverse_string(in
, len
, inform
, out_utf8
, &outlen
);
185 if ((p
= OPENSSL_malloc(outlen
+ 1)) == NULL
) {
187 ASN1_STRING_free(dest
);
190 dest
->length
= outlen
;
193 traverse_string(in
, len
, inform
, cpyfunc
, &p
);
198 * This function traverses a string and passes the value of each character to
199 * an optional function along with a void * argument.
202 static int traverse_string(const unsigned char *p
, int len
, int inform
,
203 int (*rfunc
) (unsigned long value
, void *in
),
209 if (inform
== MBSTRING_ASC
) {
212 } else if (inform
== MBSTRING_BMP
) {
216 } else if (inform
== MBSTRING_UNIV
) {
217 value
= ((unsigned long)*p
++) << 24;
218 value
|= ((unsigned long)*p
++) << 16;
223 ret
= UTF8_getc(p
, len
, &value
);
230 ret
= rfunc(value
, arg
);
238 /* Various utility functions for traverse_string */
240 /* Just count number of characters */
242 static int in_utf8(unsigned long value
, void *arg
)
246 if (!is_unicode_valid(value
))
253 /* Determine size of output as a UTF8 String */
255 static int out_utf8(unsigned long value
, void *arg
)
259 len
= UTF8_putc(NULL
, -1, value
);
268 * Determine the "type" of a string: check each character against a supplied
272 static int type_str(unsigned long value
, void *arg
)
274 unsigned long types
= *((unsigned long *)arg
);
275 const int native
= value
> INT_MAX
? INT_MAX
: ossl_fromascii(value
);
277 if ((types
& B_ASN1_NUMERICSTRING
) && !(ossl_isdigit(native
)
279 types
&= ~B_ASN1_NUMERICSTRING
;
280 if ((types
& B_ASN1_PRINTABLESTRING
) && !ossl_isasn1print(native
))
281 types
&= ~B_ASN1_PRINTABLESTRING
;
282 if ((types
& B_ASN1_IA5STRING
) && !ossl_isascii(native
))
283 types
&= ~B_ASN1_IA5STRING
;
284 if ((types
& B_ASN1_T61STRING
) && (value
> 0xff))
285 types
&= ~B_ASN1_T61STRING
;
286 if ((types
& B_ASN1_BMPSTRING
) && (value
> 0xffff))
287 types
&= ~B_ASN1_BMPSTRING
;
288 if ((types
& B_ASN1_UTF8STRING
) && !is_unicode_valid(value
))
289 types
&= ~B_ASN1_UTF8STRING
;
292 *((unsigned long *)arg
) = types
;
296 /* Copy one byte per character ASCII like strings */
298 static int cpy_asc(unsigned long value
, void *arg
)
300 unsigned char **p
, *q
;
303 *q
= (unsigned char)value
;
308 /* Copy two byte per character BMPStrings */
310 static int cpy_bmp(unsigned long value
, void *arg
)
312 unsigned char **p
, *q
;
315 *q
++ = (unsigned char)((value
>> 8) & 0xff);
316 *q
= (unsigned char)(value
& 0xff);
321 /* Copy four byte per character UniversalStrings */
323 static int cpy_univ(unsigned long value
, void *arg
)
325 unsigned char **p
, *q
;
328 *q
++ = (unsigned char)((value
>> 24) & 0xff);
329 *q
++ = (unsigned char)((value
>> 16) & 0xff);
330 *q
++ = (unsigned char)((value
>> 8) & 0xff);
331 *q
= (unsigned char)(value
& 0xff);
336 /* Copy to a UTF8String */
338 static int cpy_utf8(unsigned long value
, void *arg
)
343 /* We already know there is enough room so pass 0xff as the length */
344 ret
= UTF8_putc(*p
, 0xff, value
);