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