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