• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.] */
56 
57 #include <openssl/asn1.h>
58 
59 #include <limits.h>
60 #include <string.h>
61 
62 #include <openssl/bytestring.h>
63 #include <openssl/err.h>
64 #include <openssl/mem.h>
65 
66 #include "asn1_locl.h"
67 #include "../bytestring/internal.h"
68 
69 static int is_printable(uint32_t value);
70 
71 /*
72  * These functions take a string in UTF8, ASCII or multibyte form and a mask
73  * of permissible ASN1 string types. It then works out the minimal type
74  * (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) and
75  * creates a string of the correct type with the supplied data. Yes this is
76  * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum
77  * size limits too.
78  */
79 
ASN1_mbstring_copy(ASN1_STRING ** out,const unsigned char * in,int len,int inform,unsigned long mask)80 int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
81                        int inform, unsigned long mask)
82 {
83     return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
84 }
85 
OPENSSL_DECLARE_ERROR_REASON(ASN1,INVALID_BMPSTRING)86 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_BMPSTRING)
87 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UNIVERSALSTRING)
88 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UTF8STRING)
89 
90 int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
91                         int inform, unsigned long mask,
92                         long minsize, long maxsize)
93 {
94     int str_type;
95     char free_out;
96     ASN1_STRING *dest;
97     size_t nchar = 0;
98     char strbuf[32];
99     if (len == -1)
100         len = strlen((const char *)in);
101     if (!mask)
102         mask = DIRSTRING_TYPE;
103 
104     int (*decode_func)(CBS *, uint32_t*);
105     int error;
106     switch (inform) {
107     case MBSTRING_BMP:
108         decode_func = cbs_get_ucs2_be;
109         error = ASN1_R_INVALID_BMPSTRING;
110         break;
111 
112     case MBSTRING_UNIV:
113         decode_func = cbs_get_utf32_be;
114         error = ASN1_R_INVALID_UNIVERSALSTRING;
115         break;
116 
117     case MBSTRING_UTF8:
118         decode_func = cbs_get_utf8;
119         error = ASN1_R_INVALID_UTF8STRING;
120         break;
121 
122     case MBSTRING_ASC:
123         decode_func = cbs_get_latin1;
124         error = ERR_R_INTERNAL_ERROR;  // Latin-1 inputs are never invalid.
125         break;
126 
127     default:
128         OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT);
129         return -1;
130     }
131 
132     /* Check |minsize| and |maxsize| and work out the minimal type, if any. */
133     CBS cbs;
134     CBS_init(&cbs, in, len);
135     size_t utf8_len = 0;
136     while (CBS_len(&cbs) != 0) {
137         uint32_t c;
138         if (!decode_func(&cbs, &c)) {
139             OPENSSL_PUT_ERROR(ASN1, error);
140             return -1;
141         }
142         if (nchar == 0 &&
143             (inform == MBSTRING_BMP || inform == MBSTRING_UNIV) &&
144             c == 0xfeff) {
145             /* Reject byte-order mark. We could drop it but that would mean
146              * adding ambiguity around whether a BOM was included or not when
147              * matching strings.
148              *
149              * For a little-endian UCS-2 string, the BOM will appear as 0xfffe
150              * and will be rejected as noncharacter, below. */
151             OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
152             return -1;
153         }
154 
155         /* Update which output formats are still possible. */
156         if ((mask & B_ASN1_PRINTABLESTRING) && !is_printable(c)) {
157             mask &= ~B_ASN1_PRINTABLESTRING;
158         }
159         if ((mask & B_ASN1_IA5STRING) && (c > 127)) {
160             mask &= ~B_ASN1_IA5STRING;
161         }
162         if ((mask & B_ASN1_T61STRING) && (c > 0xff)) {
163             mask &= ~B_ASN1_T61STRING;
164         }
165         if ((mask & B_ASN1_BMPSTRING) && (c > 0xffff)) {
166             mask &= ~B_ASN1_BMPSTRING;
167         }
168         if (!mask) {
169             OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
170             return -1;
171         }
172 
173         nchar++;
174         utf8_len += cbb_get_utf8_len(c);
175     }
176 
177     if (minsize > 0 && nchar < (size_t)minsize) {
178         OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT);
179         BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
180         ERR_add_error_data(2, "minsize=", strbuf);
181         return -1;
182     }
183 
184     if (maxsize > 0 && nchar > (size_t)maxsize) {
185         OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
186         BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
187         ERR_add_error_data(2, "maxsize=", strbuf);
188         return -1;
189     }
190 
191     /* Now work out output format and string type */
192     int (*encode_func)(CBB *, uint32_t) = cbb_add_latin1;
193     size_t size_estimate = nchar;
194     int outform = MBSTRING_ASC;
195     if (mask & B_ASN1_PRINTABLESTRING) {
196         str_type = V_ASN1_PRINTABLESTRING;
197     } else if (mask & B_ASN1_IA5STRING) {
198         str_type = V_ASN1_IA5STRING;
199     } else if (mask & B_ASN1_T61STRING) {
200         str_type = V_ASN1_T61STRING;
201     } else if (mask & B_ASN1_BMPSTRING) {
202         str_type = V_ASN1_BMPSTRING;
203         outform = MBSTRING_BMP;
204         encode_func = cbb_add_ucs2_be;
205         size_estimate = 2 * nchar;
206     } else if (mask & B_ASN1_UNIVERSALSTRING) {
207         str_type = V_ASN1_UNIVERSALSTRING;
208         encode_func = cbb_add_utf32_be;
209         size_estimate = 4 * nchar;
210         outform = MBSTRING_UNIV;
211     } else {
212         str_type = V_ASN1_UTF8STRING;
213         outform = MBSTRING_UTF8;
214         encode_func = cbb_add_utf8;
215         size_estimate = utf8_len;
216     }
217 
218     if (!out)
219         return str_type;
220     if (*out) {
221         free_out = 0;
222         dest = *out;
223         if (dest->data) {
224             dest->length = 0;
225             OPENSSL_free(dest->data);
226             dest->data = NULL;
227         }
228         dest->type = str_type;
229     } else {
230         free_out = 1;
231         dest = ASN1_STRING_type_new(str_type);
232         if (!dest) {
233             OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
234             return -1;
235         }
236         *out = dest;
237     }
238 
239     /* If both the same type just copy across */
240     if (inform == outform) {
241         if (!ASN1_STRING_set(dest, in, len)) {
242             OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
243             return -1;
244         }
245         return str_type;
246     }
247 
248     CBB cbb;
249     if (!CBB_init(&cbb, size_estimate + 1)) {
250         OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
251         goto err;
252     }
253     CBS_init(&cbs, in, len);
254     while (CBS_len(&cbs) != 0) {
255         uint32_t c;
256         if (!decode_func(&cbs, &c) ||
257             !encode_func(&cbb, c)) {
258             OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
259             goto err;
260         }
261     }
262     uint8_t *data = NULL;
263     size_t data_len;
264     if (/* OpenSSL historically NUL-terminated this value with a single byte,
265          * even for |MBSTRING_BMP| and |MBSTRING_UNIV|. */
266         !CBB_add_u8(&cbb, 0) ||
267         !CBB_finish(&cbb, &data, &data_len) ||
268         data_len < 1 ||
269         data_len > INT_MAX) {
270         OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
271         OPENSSL_free(data);
272         goto err;
273     }
274     dest->length = (int)(data_len - 1);
275     dest->data = data;
276     return str_type;
277 
278  err:
279     if (free_out)
280         ASN1_STRING_free(dest);
281     CBB_cleanup(&cbb);
282     return -1;
283 }
284 
285 /* Return 1 if the character is permitted in a PrintableString */
is_printable(uint32_t value)286 static int is_printable(uint32_t value)
287 {
288     int ch;
289     if (value > 0x7f)
290         return 0;
291     ch = (int)value;
292     /*
293      * Note: we can't use 'isalnum' because certain accented characters may
294      * count as alphanumeric in some environments.
295      */
296     if ((ch >= 'a') && (ch <= 'z'))
297         return 1;
298     if ((ch >= 'A') && (ch <= 'Z'))
299         return 1;
300     if ((ch >= '0') && (ch <= '9'))
301         return 1;
302     if ((ch == ' ') || strchr("'()+,-./:=?", ch))
303         return 1;
304     return 0;
305 }
306