/src/openssl/crypto/pkcs12/p12_utl.c
Line  | Count  | Source  | 
1  |  | /*  | 
2  |  |  * Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved.  | 
3  |  |  *  | 
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  | 
8  |  |  */  | 
9  |  |  | 
10  |  | #include <stdio.h>  | 
11  |  | #include "internal/cryptlib.h"  | 
12  |  | #include <openssl/pkcs12.h>  | 
13  |  | #include "p12_local.h"  | 
14  |  | #include "crypto/pkcs7/pk7_local.h"  | 
15  |  |  | 
16  |  | /* Cheap and nasty Unicode stuff */  | 
17  |  |  | 
18  |  | unsigned char *OPENSSL_asc2uni(const char *asc, int asclen,  | 
19  |  |                                unsigned char **uni, int *unilen)  | 
20  | 0  | { | 
21  | 0  |     int ulen, i;  | 
22  | 0  |     unsigned char *unitmp;  | 
23  |  | 
  | 
24  | 0  |     if (asclen == -1)  | 
25  | 0  |         asclen = (int)strlen(asc);  | 
26  | 0  |     if (asclen < 0)  | 
27  | 0  |         return NULL;  | 
28  | 0  |     ulen = asclen * 2 + 2;  | 
29  | 0  |     if ((unitmp = OPENSSL_malloc(ulen)) == NULL)  | 
30  | 0  |         return NULL;  | 
31  | 0  |     for (i = 0; i < ulen - 2; i += 2) { | 
32  | 0  |         unitmp[i] = 0;  | 
33  | 0  |         unitmp[i + 1] = asc[i >> 1];  | 
34  | 0  |     }  | 
35  |  |     /* Make result double null terminated */  | 
36  | 0  |     unitmp[ulen - 2] = 0;  | 
37  | 0  |     unitmp[ulen - 1] = 0;  | 
38  | 0  |     if (unilen)  | 
39  | 0  |         *unilen = ulen;  | 
40  | 0  |     if (uni)  | 
41  | 0  |         *uni = unitmp;  | 
42  | 0  |     return unitmp;  | 
43  | 0  | }  | 
44  |  |  | 
45  |  | char *OPENSSL_uni2asc(const unsigned char *uni, int unilen)  | 
46  | 0  | { | 
47  | 0  |     int asclen, i;  | 
48  | 0  |     char *asctmp;  | 
49  |  |  | 
50  |  |     /* string must contain an even number of bytes */  | 
51  | 0  |     if (unilen & 1)  | 
52  | 0  |         return NULL;  | 
53  | 0  |     if (unilen < 0)  | 
54  | 0  |         return NULL;  | 
55  | 0  |     asclen = unilen / 2;  | 
56  |  |     /* If no terminating zero allow for one */  | 
57  | 0  |     if (!unilen || uni[unilen - 1])  | 
58  | 0  |         asclen++;  | 
59  | 0  |     uni++;  | 
60  | 0  |     if ((asctmp = OPENSSL_malloc(asclen)) == NULL)  | 
61  | 0  |         return NULL;  | 
62  | 0  |     for (i = 0; i < unilen; i += 2)  | 
63  | 0  |         asctmp[i >> 1] = uni[i];  | 
64  | 0  |     asctmp[asclen - 1] = 0;  | 
65  | 0  |     return asctmp;  | 
66  | 0  | }  | 
67  |  |  | 
68  |  | /*  | 
69  |  |  * OPENSSL_{utf82uni|uni2utf8} perform conversion between UTF-8 and | 
70  |  |  * PKCS#12 BMPString format, which is specified as big-endian UTF-16.  | 
71  |  |  * One should keep in mind that even though BMPString is passed as  | 
72  |  |  * unsigned char *, it's not the kind of string you can exercise e.g.  | 
73  |  |  * strlen on. Caller also has to keep in mind that its length is  | 
74  |  |  * expressed not in number of UTF-16 characters, but in number of  | 
75  |  |  * bytes the string occupies, and treat it, the length, accordingly.  | 
76  |  |  */  | 
77  |  | unsigned char *OPENSSL_utf82uni(const char *asc, int asclen,  | 
78  |  |                                 unsigned char **uni, int *unilen)  | 
79  | 0  | { | 
80  | 0  |     int ulen, i, j;  | 
81  | 0  |     unsigned char *unitmp, *ret;  | 
82  | 0  |     unsigned long utf32chr = 0;  | 
83  |  | 
  | 
84  | 0  |     if (asclen == -1)  | 
85  | 0  |         asclen = (int)strlen(asc);  | 
86  |  | 
  | 
87  | 0  |     for (ulen = 0, i = 0; i < asclen; i += j) { | 
88  | 0  |         j = UTF8_getc((const unsigned char *)asc+i, asclen-i, &utf32chr);  | 
89  |  |  | 
90  |  |         /*  | 
91  |  |          * Following condition is somewhat opportunistic is sense that  | 
92  |  |          * decoding failure is used as *indirect* indication that input  | 
93  |  |          * string might in fact be extended ASCII/ANSI/ISO-8859-X. The  | 
94  |  |          * fallback is taken in hope that it would allow to process  | 
95  |  |          * files created with previous OpenSSL version, which used the  | 
96  |  |          * naive OPENSSL_asc2uni all along. It might be worth noting  | 
97  |  |          * that probability of false positive depends on language. In  | 
98  |  |          * cases covered by ISO Latin 1 probability is very low, because  | 
99  |  |          * any printable non-ASCII alphabet letter followed by another  | 
100  |  |          * or any ASCII character will trigger failure and fallback.  | 
101  |  |          * In other cases situation can be intensified by the fact that  | 
102  |  |          * English letters are not part of alternative keyboard layout,  | 
103  |  |          * but even then there should be plenty of pairs that trigger  | 
104  |  |          * decoding failure...  | 
105  |  |          */  | 
106  | 0  |         if (j < 0)  | 
107  | 0  |             return OPENSSL_asc2uni(asc, asclen, uni, unilen);  | 
108  |  |  | 
109  | 0  |         if (utf32chr > 0x10FFFF)        /* UTF-16 cap */  | 
110  | 0  |             return NULL;  | 
111  |  |  | 
112  | 0  |         if (utf32chr >= 0x10000)        /* pair of UTF-16 characters */  | 
113  | 0  |             ulen += 2*2;  | 
114  | 0  |         else                            /* or just one */  | 
115  | 0  |             ulen += 2;  | 
116  | 0  |     }  | 
117  |  |  | 
118  | 0  |     ulen += 2;  /* for trailing UTF16 zero */  | 
119  |  | 
  | 
120  | 0  |     if ((ret = OPENSSL_malloc(ulen)) == NULL)  | 
121  | 0  |         return NULL;  | 
122  |  |     /* re-run the loop writing down UTF-16 characters in big-endian order */  | 
123  | 0  |     for (unitmp = ret, i = 0; i < asclen; i += j) { | 
124  | 0  |         j = UTF8_getc((const unsigned char *)asc+i, asclen-i, &utf32chr);  | 
125  | 0  |         if (utf32chr >= 0x10000) {      /* pair if UTF-16 characters */ | 
126  | 0  |             unsigned int hi, lo;  | 
127  |  | 
  | 
128  | 0  |             utf32chr -= 0x10000;  | 
129  | 0  |             hi = 0xD800 + (utf32chr>>10);  | 
130  | 0  |             lo = 0xDC00 + (utf32chr&0x3ff);  | 
131  | 0  |             *unitmp++ = (unsigned char)(hi>>8);  | 
132  | 0  |             *unitmp++ = (unsigned char)(hi);  | 
133  | 0  |             *unitmp++ = (unsigned char)(lo>>8);  | 
134  | 0  |             *unitmp++ = (unsigned char)(lo);  | 
135  | 0  |         } else {                        /* or just one */ | 
136  | 0  |             *unitmp++ = (unsigned char)(utf32chr>>8);  | 
137  | 0  |             *unitmp++ = (unsigned char)(utf32chr);  | 
138  | 0  |         }  | 
139  | 0  |     }  | 
140  |  |     /* Make result double null terminated */  | 
141  | 0  |     *unitmp++ = 0;  | 
142  | 0  |     *unitmp++ = 0;  | 
143  | 0  |     if (unilen)  | 
144  | 0  |         *unilen = ulen;  | 
145  | 0  |     if (uni)  | 
146  | 0  |         *uni = ret;  | 
147  | 0  |     return ret;  | 
148  | 0  | }  | 
149  |  |  | 
150  |  | static int bmp_to_utf8(char *str, const unsigned char *utf16, int len)  | 
151  | 0  | { | 
152  | 0  |     unsigned long utf32chr;  | 
153  |  | 
  | 
154  | 0  |     if (len == 0) return 0;  | 
155  |  |  | 
156  | 0  |     if (len < 2) return -1;  | 
157  |  |  | 
158  |  |     /* pull UTF-16 character in big-endian order */  | 
159  | 0  |     utf32chr = (utf16[0]<<8) | utf16[1];  | 
160  |  | 
  | 
161  | 0  |     if (utf32chr >= 0xD800 && utf32chr < 0xE000) {   /* two chars */ | 
162  | 0  |         unsigned int lo;  | 
163  |  | 
  | 
164  | 0  |         if (len < 4) return -1;  | 
165  |  |  | 
166  | 0  |         utf32chr -= 0xD800;  | 
167  | 0  |         utf32chr <<= 10;  | 
168  | 0  |         lo = (utf16[2]<<8) | utf16[3];  | 
169  | 0  |         if (lo < 0xDC00 || lo >= 0xE000) return -1;  | 
170  | 0  |         utf32chr |= lo-0xDC00;  | 
171  | 0  |         utf32chr += 0x10000;  | 
172  | 0  |     }  | 
173  |  |  | 
174  | 0  |     return UTF8_putc((unsigned char *)str, len > 4 ? 4 : len, utf32chr);  | 
175  | 0  | }  | 
176  |  |  | 
177  |  | char *OPENSSL_uni2utf8(const unsigned char *uni, int unilen)  | 
178  | 0  | { | 
179  | 0  |     int asclen, i, j;  | 
180  | 0  |     char *asctmp;  | 
181  |  |  | 
182  |  |     /* string must contain an even number of bytes */  | 
183  | 0  |     if (unilen & 1)  | 
184  | 0  |         return NULL;  | 
185  |  |  | 
186  | 0  |     for (asclen = 0, i = 0; i < unilen; ) { | 
187  | 0  |         j = bmp_to_utf8(NULL, uni+i, unilen-i);  | 
188  |  |         /*  | 
189  |  |          * falling back to OPENSSL_uni2asc makes lesser sense [than  | 
190  |  |          * falling back to OPENSSL_asc2uni in OPENSSL_utf82uni above],  | 
191  |  |          * it's done rather to maintain symmetry...  | 
192  |  |          */  | 
193  | 0  |         if (j < 0) return OPENSSL_uni2asc(uni, unilen);  | 
194  | 0  |         if (j == 4) i += 4;  | 
195  | 0  |         else        i += 2;  | 
196  | 0  |         asclen += j;  | 
197  | 0  |     }  | 
198  |  |  | 
199  |  |     /* If no terminating zero allow for one */  | 
200  | 0  |     if (!unilen || (uni[unilen-2]||uni[unilen - 1]))  | 
201  | 0  |         asclen++;  | 
202  |  | 
  | 
203  | 0  |     if ((asctmp = OPENSSL_malloc(asclen)) == NULL)  | 
204  | 0  |         return NULL;  | 
205  |  |  | 
206  |  |     /* re-run the loop emitting UTF-8 string */  | 
207  | 0  |     for (asclen = 0, i = 0; i < unilen; ) { | 
208  | 0  |         j = bmp_to_utf8(asctmp+asclen, uni+i, unilen-i);  | 
209  | 0  |         if (j == 4) i += 4;  | 
210  | 0  |         else        i += 2;  | 
211  | 0  |         asclen += j;  | 
212  | 0  |     }  | 
213  |  |  | 
214  |  |     /* If no terminating zero write one */  | 
215  | 0  |     if (!unilen || (uni[unilen-2]||uni[unilen - 1]))  | 
216  | 0  |         asctmp[asclen] = '\0';  | 
217  |  | 
  | 
218  | 0  |     return asctmp;  | 
219  | 0  | }  | 
220  |  |  | 
221  |  | int i2d_PKCS12_bio(BIO *bp, const PKCS12 *p12)  | 
222  | 0  | { | 
223  | 0  |     return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS12), bp, p12);  | 
224  | 0  | }  | 
225  |  |  | 
226  |  | #ifndef OPENSSL_NO_STDIO  | 
227  |  | int i2d_PKCS12_fp(FILE *fp, const PKCS12 *p12)  | 
228  | 0  | { | 
229  | 0  |     return ASN1_item_i2d_fp(ASN1_ITEM_rptr(PKCS12), fp, p12);  | 
230  | 0  | }  | 
231  |  | #endif  | 
232  |  |  | 
233  |  | PKCS12 *d2i_PKCS12_bio(BIO *bp, PKCS12 **p12)  | 
234  | 0  | { | 
235  | 0  |     OSSL_LIB_CTX *libctx = NULL;  | 
236  | 0  |     const char *propq = NULL;  | 
237  | 0  |     const PKCS7_CTX *p7ctx = NULL;  | 
238  |  | 
  | 
239  | 0  |     if (p12 != NULL) { | 
240  | 0  |         p7ctx = ossl_pkcs12_get0_pkcs7ctx(*p12);  | 
241  | 0  |         if (p7ctx != NULL) { | 
242  | 0  |             libctx = ossl_pkcs7_ctx_get0_libctx(p7ctx);  | 
243  | 0  |             propq = ossl_pkcs7_ctx_get0_propq(p7ctx);  | 
244  | 0  |         }  | 
245  | 0  |     }  | 
246  | 0  |     return ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(PKCS12), bp, p12, libctx, propq);  | 
247  | 0  | }  | 
248  |  |  | 
249  |  | #ifndef OPENSSL_NO_STDIO  | 
250  |  | PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12)  | 
251  | 0  | { | 
252  | 0  |     OSSL_LIB_CTX *libctx = NULL;  | 
253  | 0  |     const char *propq = NULL;  | 
254  | 0  |     const PKCS7_CTX *p7ctx = NULL;  | 
255  |  | 
  | 
256  | 0  |     if (p12 != NULL) { | 
257  | 0  |         p7ctx = ossl_pkcs12_get0_pkcs7ctx(*p12);  | 
258  | 0  |         if (p7ctx != NULL) { | 
259  | 0  |             libctx = ossl_pkcs7_ctx_get0_libctx(p7ctx);  | 
260  | 0  |             propq = ossl_pkcs7_ctx_get0_propq(p7ctx);  | 
261  | 0  |         }  | 
262  | 0  |     }  | 
263  | 0  |     return ASN1_item_d2i_fp_ex(ASN1_ITEM_rptr(PKCS12), fp, p12, libctx, propq);  | 
264  | 0  | }  | 
265  |  | #endif  |