• 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 "internal.h"
67 #include "../bytestring/internal.h"
68 
69 /*
70  * These functions take a string in UTF8, ASCII or multibyte form and a mask
71  * of permissible ASN1 string types. It then works out the minimal type
72  * (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) and
73  * creates a string of the correct type with the supplied data. Yes this is
74  * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum
75  * size limits too.
76  */
77 
ASN1_mbstring_copy(ASN1_STRING ** out,const unsigned char * in,int len,int inform,unsigned long mask)78 int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
79                        int inform, unsigned long mask)
80 {
81     return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
82 }
83 
OPENSSL_DECLARE_ERROR_REASON(ASN1,INVALID_BMPSTRING)84 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_BMPSTRING)
85 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UNIVERSALSTRING)
86 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UTF8STRING)
87 
88 int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
89                         int inform, unsigned long mask,
90                         long minsize, long maxsize)
91 {
92     int str_type;
93     char free_out;
94     ASN1_STRING *dest;
95     size_t nchar = 0;
96     char strbuf[32];
97     if (len == -1)
98         len = strlen((const char *)in);
99     if (!mask)
100         mask = DIRSTRING_TYPE;
101 
102     int (*decode_func)(CBS *, uint32_t*);
103     int error;
104     switch (inform) {
105     case MBSTRING_BMP:
106         decode_func = cbs_get_ucs2_be;
107         error = ASN1_R_INVALID_BMPSTRING;
108         break;
109 
110     case MBSTRING_UNIV:
111         decode_func = cbs_get_utf32_be;
112         error = ASN1_R_INVALID_UNIVERSALSTRING;
113         break;
114 
115     case MBSTRING_UTF8:
116         decode_func = cbs_get_utf8;
117         error = ASN1_R_INVALID_UTF8STRING;
118         break;
119 
120     case MBSTRING_ASC:
121         decode_func = cbs_get_latin1;
122         error = ERR_R_INTERNAL_ERROR;  // Latin-1 inputs are never invalid.
123         break;
124 
125     default:
126         OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT);
127         return -1;
128     }
129 
130     /* Check |minsize| and |maxsize| and work out the minimal type, if any. */
131     CBS cbs;
132     CBS_init(&cbs, in, len);
133     size_t utf8_len = 0;
134     while (CBS_len(&cbs) != 0) {
135         uint32_t c;
136         if (!decode_func(&cbs, &c)) {
137             OPENSSL_PUT_ERROR(ASN1, error);
138             return -1;
139         }
140         if (nchar == 0 &&
141             (inform == MBSTRING_BMP || inform == MBSTRING_UNIV) &&
142             c == 0xfeff) {
143             /* Reject byte-order mark. We could drop it but that would mean
144              * adding ambiguity around whether a BOM was included or not when
145              * matching strings.
146              *
147              * For a little-endian UCS-2 string, the BOM will appear as 0xfffe
148              * and will be rejected as noncharacter, below. */
149             OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
150             return -1;
151         }
152 
153         /* Update which output formats are still possible. */
154         if ((mask & B_ASN1_PRINTABLESTRING) && !asn1_is_printable(c)) {
155             mask &= ~B_ASN1_PRINTABLESTRING;
156         }
157         if ((mask & B_ASN1_IA5STRING) && (c > 127)) {
158             mask &= ~B_ASN1_IA5STRING;
159         }
160         if ((mask & B_ASN1_T61STRING) && (c > 0xff)) {
161             mask &= ~B_ASN1_T61STRING;
162         }
163         if ((mask & B_ASN1_BMPSTRING) && (c > 0xffff)) {
164             mask &= ~B_ASN1_BMPSTRING;
165         }
166         if (!mask) {
167             OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
168             return -1;
169         }
170 
171         nchar++;
172         utf8_len += cbb_get_utf8_len(c);
173     }
174 
175     if (minsize > 0 && nchar < (size_t)minsize) {
176         OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT);
177         BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
178         ERR_add_error_data(2, "minsize=", strbuf);
179         return -1;
180     }
181 
182     if (maxsize > 0 && nchar > (size_t)maxsize) {
183         OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
184         BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
185         ERR_add_error_data(2, "maxsize=", strbuf);
186         return -1;
187     }
188 
189     /* Now work out output format and string type */
190     int (*encode_func)(CBB *, uint32_t) = cbb_add_latin1;
191     size_t size_estimate = nchar;
192     int outform = MBSTRING_ASC;
193     if (mask & B_ASN1_PRINTABLESTRING) {
194         str_type = V_ASN1_PRINTABLESTRING;
195     } else if (mask & B_ASN1_IA5STRING) {
196         str_type = V_ASN1_IA5STRING;
197     } else if (mask & B_ASN1_T61STRING) {
198         str_type = V_ASN1_T61STRING;
199     } else if (mask & B_ASN1_BMPSTRING) {
200         str_type = V_ASN1_BMPSTRING;
201         outform = MBSTRING_BMP;
202         encode_func = cbb_add_ucs2_be;
203         size_estimate = 2 * nchar;
204     } else if (mask & B_ASN1_UNIVERSALSTRING) {
205         str_type = V_ASN1_UNIVERSALSTRING;
206         encode_func = cbb_add_utf32_be;
207         size_estimate = 4 * nchar;
208         outform = MBSTRING_UNIV;
209     } else if (mask & B_ASN1_UTF8STRING) {
210         str_type = V_ASN1_UTF8STRING;
211         outform = MBSTRING_UTF8;
212         encode_func = cbb_add_utf8;
213         size_estimate = utf8_len;
214     } else {
215         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
216         return -1;
217     }
218 
219     if (!out)
220         return str_type;
221     if (*out) {
222         free_out = 0;
223         dest = *out;
224         if (dest->data) {
225             dest->length = 0;
226             OPENSSL_free(dest->data);
227             dest->data = NULL;
228         }
229         dest->type = str_type;
230     } else {
231         free_out = 1;
232         dest = ASN1_STRING_type_new(str_type);
233         if (!dest) {
234             OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
235             return -1;
236         }
237         *out = dest;
238     }
239 
240     /* If both the same type just copy across */
241     if (inform == outform) {
242         if (!ASN1_STRING_set(dest, in, len)) {
243             OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
244             return -1;
245         }
246         return str_type;
247     }
248 
249     CBB cbb;
250     if (!CBB_init(&cbb, size_estimate + 1)) {
251         OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
252         goto err;
253     }
254     CBS_init(&cbs, in, len);
255     while (CBS_len(&cbs) != 0) {
256         uint32_t c;
257         if (!decode_func(&cbs, &c) ||
258             !encode_func(&cbb, c)) {
259             OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
260             goto err;
261         }
262     }
263     uint8_t *data = NULL;
264     size_t data_len;
265     if (/* OpenSSL historically NUL-terminated this value with a single byte,
266          * even for |MBSTRING_BMP| and |MBSTRING_UNIV|. */
267         !CBB_add_u8(&cbb, 0) ||
268         !CBB_finish(&cbb, &data, &data_len) ||
269         data_len < 1 ||
270         data_len > INT_MAX) {
271         OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
272         OPENSSL_free(data);
273         goto err;
274     }
275     dest->length = (int)(data_len - 1);
276     dest->data = data;
277     return str_type;
278 
279  err:
280     if (free_out)
281         ASN1_STRING_free(dest);
282     CBB_cleanup(&cbb);
283     return -1;
284 }
285 
asn1_is_printable(uint32_t value)286 int asn1_is_printable(uint32_t value)
287 {
288     if (value > 0x7f) {
289         return 0;
290     }
291     /* Note we cannot use |isalnum| because it is locale-dependent. */
292     return ('a' <= value && value <= 'z') ||  //
293            ('A' <= value && value <= 'Z') ||  //
294            ('0' <= value && value <= '9') ||  //
295            value == ' ' || value == '\'' || value == '(' || value == ')' ||
296            value == '+' || value == ',' || value == '-' || value == '.' ||
297            value == '/' || value == ':' || value == '=' || value == '?';
298 }
299