The branch master has been updated via 1194ea8dc3b51a35c9947ed276f38436abee5743 (commit) via b799aef863a81c9a9d5dbffae12cca912ae348b2 (commit) via 70bf33d1821baf44764555be6a63488798c4d086 (commit) via 9e6b2f54e449009c6dc11e8860d125d967f3a3ed (commit) from 5cb4d6466a14665f8cd659b6dd7746183f2c60bd (commit)
- Log ----------------------------------------------------------------- commit 1194ea8dc3b51a35c9947ed276f38436abee5743 Author: Andy Polyakov <ap...@openssl.org> Date: Tue Jul 26 16:42:41 2016 +0200 crypto/pkcs12: facilitate accessing data with non-interoperable password. Originally PKCS#12 subroutines treated password strings as ASCII. It worked as long as they were pure ASCII, but if there were some none-ASCII characters result was non-interoperable. But fixing it poses problem accessing data protected with broken password. In order to make asscess to old data possible add retry with old-style password. Reviewed-by: Richard Levitte <levi...@openssl.org> commit b799aef863a81c9a9d5dbffae12cca912ae348b2 Author: Andy Polyakov <ap...@openssl.org> Date: Tue Jul 26 01:48:01 2016 +0200 crypto/pkcs12: default to UTF-8. Reviewed-by: Richard Levitte <levi...@openssl.org> commit 70bf33d1821baf44764555be6a63488798c4d086 Author: Andy Polyakov <ap...@openssl.org> Date: Tue Jul 26 01:46:03 2016 +0200 Add PKCS#12 UTF-8 interoperability test. Reviewed-by: Richard Levitte <levi...@openssl.org> commit 9e6b2f54e449009c6dc11e8860d125d967f3a3ed Author: Andy Polyakov <ap...@openssl.org> Date: Tue Nov 24 23:34:51 2015 +0100 crypto/pkcs12: add UTF8 support. Reviewed-by: Richard Levitte <levi...@openssl.org> ----------------------------------------------------------------------- Summary of changes: .gitattributes | 1 + crypto/pkcs12/p12_attr.c | 14 +++- crypto/pkcs12/p12_crpt.c | 31 +++++++-- crypto/pkcs12/p12_key.c | 23 +++++++ crypto/pkcs12/p12_lcl.h | 9 +++ crypto/pkcs12/p12_mutl.c | 84 ++++++++++++++++++++--- crypto/pkcs12/p12_utl.c | 156 +++++++++++++++++++++++++++++++++++++++++- crypto/pkcs12/pk12err.c | 1 + doc/apps/pkcs12.pod | 10 +++ include/openssl/pkcs12.h | 27 ++++---- test/recipes/80-test_pkcs12.t | 42 ++++++++++++ test/shibboleth.pfx | Bin 0 -> 2519 bytes util/libcrypto.num | 4 ++ 13 files changed, 373 insertions(+), 29 deletions(-) create mode 100644 test/recipes/80-test_pkcs12.t create mode 100644 test/shibboleth.pfx diff --git a/.gitattributes b/.gitattributes index f33e22a..15121c8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ *.der binary /fuzz/corpora/** binary +*.pfx binary diff --git a/crypto/pkcs12/p12_attr.c b/crypto/pkcs12/p12_attr.c index a16231f..c324f50 100644 --- a/crypto/pkcs12/p12_attr.c +++ b/crypto/pkcs12/p12_attr.c @@ -45,6 +45,16 @@ int PKCS12_add_friendlyname_asc(PKCS12_SAFEBAG *bag, const char *name, return 0; } +int PKCS12_add_friendlyname_utf8(PKCS12_SAFEBAG *bag, const char *name, + int namelen) +{ + if (X509at_add1_attr_by_NID(&bag->attrib, NID_friendlyName, + MBSTRING_UTF8, (unsigned char *)name, namelen)) + return 1; + else + return 0; +} + int PKCS12_add_friendlyname_uni(PKCS12_SAFEBAG *bag, const unsigned char *name, int namelen) { @@ -82,8 +92,8 @@ char *PKCS12_get_friendlyname(PKCS12_SAFEBAG *bag) return NULL; if (atype->type != V_ASN1_BMPSTRING) return NULL; - return OPENSSL_uni2asc(atype->value.bmpstring->data, - atype->value.bmpstring->length); + return OPENSSL_uni2utf8(atype->value.bmpstring->data, + atype->value.bmpstring->length); } const STACK_OF(X509_ATTRIBUTE) * diff --git a/crypto/pkcs12/p12_crpt.c b/crypto/pkcs12/p12_crpt.c index 1fe140a..d30aab3 100644 --- a/crypto/pkcs12/p12_crpt.c +++ b/crypto/pkcs12/p12_crpt.c @@ -17,6 +17,16 @@ void PKCS12_PBE_add(void) { } +#undef PKCS12_key_gen +/* + * See p12_multi.c:PKCS12_verify_mac() for details... + */ +extern int (*PKCS12_key_gen)(const char *pass, int passlen, + unsigned char *salt, int slen, + int id, int iter, int n, + unsigned char *out, + const EVP_MD *md_type); + int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md, int en_de) @@ -25,6 +35,19 @@ int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, int saltlen, iter, ret; unsigned char *salt; unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; + int (*pkcs12_key_gen)(const char *pass, int passlen, + unsigned char *salt, int slen, + int id, int iter, int n, + unsigned char *out, + const EVP_MD *md_type); + + if (PKCS12_key_gen == NULL || en_de) + /* + * Default to UTF-8, but force it in encrypt case. + */ + pkcs12_key_gen = PKCS12_key_gen_utf8; + else + pkcs12_key_gen = PKCS12_key_gen; if (cipher == NULL) return 0; @@ -43,14 +66,14 @@ int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, iter = ASN1_INTEGER_get(pbe->iter); salt = pbe->salt->data; saltlen = pbe->salt->length; - if (!PKCS12_key_gen(pass, passlen, salt, saltlen, PKCS12_KEY_ID, - iter, EVP_CIPHER_key_length(cipher), key, md)) { + if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_KEY_ID, + iter, EVP_CIPHER_key_length(cipher), key, md)) { PKCS12err(PKCS12_F_PKCS12_PBE_KEYIVGEN, PKCS12_R_KEY_GEN_ERROR); PBEPARAM_free(pbe); return 0; } - if (!PKCS12_key_gen(pass, passlen, salt, saltlen, PKCS12_IV_ID, - iter, EVP_CIPHER_iv_length(cipher), iv, md)) { + if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_IV_ID, + iter, EVP_CIPHER_iv_length(cipher), iv, md)) { PKCS12err(PKCS12_F_PKCS12_PBE_KEYIVGEN, PKCS12_R_IV_GEN_ERROR); PBEPARAM_free(pbe); return 0; diff --git a/crypto/pkcs12/p12_key.c b/crypto/pkcs12/p12_key.c index 4f1d29b..9c13a45 100644 --- a/crypto/pkcs12/p12_key.c +++ b/crypto/pkcs12/p12_key.c @@ -50,6 +50,29 @@ int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt, return ret; } +int PKCS12_key_gen_utf8(const char *pass, int passlen, unsigned char *salt, + int saltlen, int id, int iter, int n, + unsigned char *out, const EVP_MD *md_type) +{ + int ret; + unsigned char *unipass; + int uniplen; + + if (!pass) { + unipass = NULL; + uniplen = 0; + } else if (!OPENSSL_utf82uni(pass, passlen, &unipass, &uniplen)) { + PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UTF8, ERR_R_MALLOC_FAILURE); + return 0; + } + ret = PKCS12_key_gen_uni(unipass, uniplen, salt, saltlen, + id, iter, n, out, md_type); + if (ret <= 0) + return 0; + OPENSSL_clear_free(unipass, uniplen); + return ret; +} + int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type) diff --git a/crypto/pkcs12/p12_lcl.h b/crypto/pkcs12/p12_lcl.h index 8930875..9a27f2f 100644 --- a/crypto/pkcs12/p12_lcl.h +++ b/crypto/pkcs12/p12_lcl.h @@ -42,3 +42,12 @@ struct pkcs12_bag_st { } value; }; +#undef PKCS12_key_gen +/* + * See p12_multi.c:PKCS12_verify_mac() for details... + */ +extern int (*PKCS12_key_gen)(const char *pass, int passlen, + unsigned char *salt, int slen, + int id, int iter, int n, + unsigned char *out, + const EVP_MD *md_type); diff --git a/crypto/pkcs12/p12_mutl.c b/crypto/pkcs12/p12_mutl.c index 79639c2..325da0c 100644 --- a/crypto/pkcs12/p12_mutl.c +++ b/crypto/pkcs12/p12_mutl.c @@ -66,9 +66,40 @@ static int pkcs12_gen_gost_mac_key(const char *pass, int passlen, return 1; } +#undef PKCS12_key_gen +/* + * |PKCS12_key_gen| is used to convey information about old-style broken + * password being used to PKCS12_PBE_keyivgen in decrypt cases. Workflow + * is if PKCS12_verify_mac notes that password encoded with compliant + * PKCS12_key_gen_utf8 conversion subroutine isn't right, while encoded + * with legacy non-compliant one is, then it sets |PKCS12_key_gen| to + * legacy PKCS12_key_gen_asc conversion subroutine, which is then picked + * by PKCS12_PBE_keyivgen. This applies to reading data. Written data + * on the other hand is protected with standard-compliant encoding, i.e. + * in backward-incompatible manner. Note that formally the approach is + * not MT-safe. Rationale is that in order to access PKCS#12 files from + * MT or even production application, you would be required to convert + * data to correct interoperable format. In which case this variable + * won't have to change. Conversion would have to be done with pkcs12 + * utility, which is not MT, and hence can tolerate it. In other words + * goal is not to make this heuristic approach work in general case, + * but in one specific one, apps/pkcs12.c. + */ +int (*PKCS12_key_gen)(const char *pass, int passlen, + unsigned char *salt, int slen, + int id, int iter, int n, + unsigned char *out, + const EVP_MD *md_type) = NULL; + + /* Generate a MAC */ -int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen, - unsigned char *mac, unsigned int *maclen) +static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen, + unsigned char *mac, unsigned int *maclen, + int (*pkcs12_key_gen)(const char *pass, int passlen, + unsigned char *salt, int slen, + int id, int iter, int n, + unsigned char *out, + const EVP_MD *md_type)) { const EVP_MD *md_type; HMAC_CTX *hmac = NULL; @@ -79,6 +110,11 @@ int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen, const X509_ALGOR *macalg; const ASN1_OBJECT *macoid; + if (pkcs12_key_gen == NULL) + pkcs12_key_gen = PKCS12_key_gen; + if (pkcs12_key_gen == NULL) + pkcs12_key_gen = PKCS12_key_gen_utf8; + if (!PKCS7_type_is_data(p12->authsafes)) { PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_CONTENT_TYPE_NOT_DATA); return 0; @@ -111,8 +147,8 @@ int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen, return 0; } } else - if (!PKCS12_key_gen(pass, passlen, salt, saltlen, PKCS12_MAC_ID, iter, - md_size, key, md_type)) { + if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_MAC_ID, + iter, md_size, key, md_type)) { PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_KEY_GEN_ERROR); return 0; } @@ -128,6 +164,12 @@ int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen, return 1; } +int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen, + unsigned char *mac, unsigned int *maclen) +{ + return pkcs12_gen_mac(p12, pass, passlen, mac, maclen, NULL); +} + /* Verify the mac */ int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen) { @@ -139,14 +181,36 @@ int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen) PKCS12err(PKCS12_F_PKCS12_VERIFY_MAC, PKCS12_R_MAC_ABSENT); return 0; } - if (!PKCS12_gen_mac(p12, pass, passlen, mac, &maclen)) { + if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen, + PKCS12_key_gen_utf8)) { PKCS12err(PKCS12_F_PKCS12_VERIFY_MAC, PKCS12_R_MAC_GENERATION_ERROR); return 0; } X509_SIG_get0(p12->mac->dinfo, NULL, &macoct); - if ((maclen != (unsigned int)ASN1_STRING_length(macoct)) - || CRYPTO_memcmp(mac, ASN1_STRING_get0_data(macoct), maclen)) + if (maclen != (unsigned int)ASN1_STRING_length(macoct)) return 0; + + if (CRYPTO_memcmp(mac, ASN1_STRING_get0_data(macoct), maclen) != 0) { + if (pass == NULL) + return 0; + /* + * In order to facilitate accessing old data retry with + * old-style broken password ... + */ + if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen, + PKCS12_key_gen_asc)) { + PKCS12err(PKCS12_F_PKCS12_VERIFY_MAC, PKCS12_R_MAC_GENERATION_ERROR); + return 0; + } + if ((maclen != (unsigned int)ASN1_STRING_length(macoct)) + || CRYPTO_memcmp(mac, ASN1_STRING_get0_data(macoct), maclen) != 0) + return 0; + else + PKCS12_key_gen = PKCS12_key_gen_asc; + /* + * ... and if suceeded, pass it on to PKCS12_PBE_keyivgen. + */ + } return 1; } @@ -166,7 +230,11 @@ int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen, PKCS12err(PKCS12_F_PKCS12_SET_MAC, PKCS12_R_MAC_SETUP_ERROR); return 0; } - if (!PKCS12_gen_mac(p12, pass, passlen, mac, &maclen)) { + /* + * Note that output mac is forced to UTF-8... + */ + if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen, + PKCS12_key_gen_utf8)) { PKCS12err(PKCS12_F_PKCS12_SET_MAC, PKCS12_R_MAC_GENERATION_ERROR); return 0; } diff --git a/crypto/pkcs12/p12_utl.c b/crypto/pkcs12/p12_utl.c index c4feb90..0701478 100644 --- a/crypto/pkcs12/p12_utl.c +++ b/crypto/pkcs12/p12_utl.c @@ -38,7 +38,7 @@ unsigned char *OPENSSL_asc2uni(const char *asc, int asclen, return unitmp; } -char *OPENSSL_uni2asc(unsigned char *uni, int unilen) +char *OPENSSL_uni2asc(const unsigned char *uni, int unilen) { int asclen, i; char *asctmp; @@ -58,6 +58,160 @@ char *OPENSSL_uni2asc(unsigned char *uni, int unilen) return asctmp; } +/* + * OPENSSL_{utf82uni|uni2utf8} perform conversion between UTF-8 and + * PKCS#12 BMPString format, which is specified as big-endian UTF-16. + * One should keep in mind that even though BMPString is passed as + * unsigned char *, it's not the kind of string you can exercise e.g. + * strlen on. Caller also has to keep in mind that its length is + * expressed not in number of UTF-16 characters, but in number of + * bytes the string occupies, and treat it, the length, accordingly. + */ +unsigned char *OPENSSL_utf82uni(const char *asc, int asclen, + unsigned char **uni, int *unilen) +{ + int ulen, i, j; + unsigned char *unitmp, *ret; + unsigned long utf32chr = 0; + + if (asclen == -1) + asclen = strlen(asc); + + for (ulen = 0, i = 0; i < asclen; i += j) { + j = UTF8_getc((const unsigned char *)asc+i, asclen-i, &utf32chr); + + /* + * Following condition is somewhat opportunistic is sense that + * decoding failure is used as *indirect* indication that input + * string might in fact be extended ASCII/ANSI/ISO-8859-X. The + * fallback is taken in hope that it would allow to process + * files created with previous OpenSSL version, which used the + * naive OPENSSL_asc2uni all along. It might be worth noting + * that probability of false positive depends on language. In + * cases covered by ISO Latin 1 probability is very low, because + * any printable non-ASCII alphabet letter followed by another + * or any ASCII character will trigger failure and fallback. + * In other cases situation can be intensified by the fact that + * English letters are not part of alternative keyboard layout, + * but even then there should be plenty of pairs that trigger + * decoding failure... + */ + if (j < 0) + return OPENSSL_asc2uni(asc, asclen, uni, unilen); + + if (utf32chr > 0x10FFFF) /* UTF-16 cap */ + return NULL; + + if (utf32chr >= 0x10000) /* pair of UTF-16 characters */ + ulen += 2*2; + else /* or just one */ + ulen += 2; + } + + ulen += 2; /* for trailing UTF16 zero */ + + if ((ret = OPENSSL_malloc(ulen)) == NULL) + return NULL; + + /* re-run the loop writing down UTF-16 characters in big-endian order */ + for (unitmp = ret, i = 0; i < asclen; i += j) { + j = UTF8_getc((const unsigned char *)asc+i, asclen-i, &utf32chr); + if (utf32chr >= 0x10000) { /* pair if UTF-16 characters */ + unsigned int hi, lo; + + utf32chr -= 0x10000; + hi = 0xD800 + (utf32chr>>10); + lo = 0xDC00 + (utf32chr&0x3ff); + *unitmp++ = (unsigned char)(hi>>8); + *unitmp++ = (unsigned char)(hi); + *unitmp++ = (unsigned char)(lo>>8); + *unitmp++ = (unsigned char)(lo); + } else { /* or just one */ + *unitmp++ = (unsigned char)(utf32chr>>8); + *unitmp++ = (unsigned char)(utf32chr); + } + } + /* Make result double null terminated */ + *unitmp++ = 0; + *unitmp++ = 0; + if (unilen) + *unilen = ulen; + if (uni) + *uni = ret; + return ret; +} + +static int bmp_to_utf8(char *str, const unsigned char *utf16, int len) +{ + unsigned long utf32chr; + + if (len == 0) return 0; + + if (len < 2) return -1; + + /* pull UTF-16 character in big-endian order */ + utf32chr = (utf16[0]<<8) | utf16[1]; + + if (utf32chr >= 0xD800 && utf32chr < 0xE000) { /* two chars */ + unsigned int lo; + + if (len < 4) return -1; + + utf32chr -= 0xD800; + utf32chr <<= 10; + lo = (utf16[2]<<8) | utf16[3]; + if (lo < 0xDC00 || lo >= 0xE000) return -1; + utf32chr |= lo-0xDC00; + utf32chr += 0x10000; + } + + return UTF8_putc((unsigned char *)str, len > 4 ? 4 : len, utf32chr); +} + +char *OPENSSL_uni2utf8(const unsigned char *uni, int unilen) +{ + int asclen, i, j; + char *asctmp; + + /* string must contain an even number of bytes */ + if (unilen & 1) + return NULL; + + for (asclen = 0, i = 0; i < unilen; ) { + j = bmp_to_utf8(NULL, uni+i, unilen-i); + /* + * falling back to OPENSSL_uni2asc makes lesser sense [than + * falling back to OPENSSL_asc2uni in OPENSSL_utf82uni above], + * it's done rather to maintain symmetry... + */ + if (j < 0) return OPENSSL_uni2asc(uni, unilen); + if (j == 4) i += 4; + else i += 2; + asclen += j; + } + + /* If no terminating zero allow for one */ + if (!unilen || (uni[unilen-2]||uni[unilen - 1])) + asclen++; + + if ((asctmp = OPENSSL_malloc(asclen)) == NULL) + return NULL; + + /* re-run the loop emitting UTF-8 string */ + for (asclen = 0, i = 0; i < unilen; ) { + j = bmp_to_utf8(asctmp+asclen, uni+i, unilen-i); + if (j == 4) i += 4; + else i += 2; + asclen += j; + } + + /* If no terminating zero write one */ + if (!unilen || (uni[unilen-2]||uni[unilen - 1])) + asctmp[asclen] = '\0'; + + return asctmp; +} + int i2d_PKCS12_bio(BIO *bp, PKCS12 *p12) { return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS12), bp, p12); diff --git a/crypto/pkcs12/pk12err.c b/crypto/pkcs12/pk12err.c index f15a695..f705084 100644 --- a/crypto/pkcs12/pk12err.c +++ b/crypto/pkcs12/pk12err.c @@ -27,6 +27,7 @@ static ERR_STRING_DATA PKCS12_str_functs[] = { {ERR_FUNC(PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG), "PKCS12_item_pack_safebag"}, {ERR_FUNC(PKCS12_F_PKCS12_KEY_GEN_ASC), "PKCS12_key_gen_asc"}, {ERR_FUNC(PKCS12_F_PKCS12_KEY_GEN_UNI), "PKCS12_key_gen_uni"}, + {ERR_FUNC(PKCS12_F_PKCS12_KEY_GEN_UTF8), "PKCS12_key_gen_utf8"}, {ERR_FUNC(PKCS12_F_PKCS12_NEWPASS), "PKCS12_newpass"}, {ERR_FUNC(PKCS12_F_PKCS12_PACK_P7DATA), "PKCS12_pack_p7data"}, {ERR_FUNC(PKCS12_F_PKCS12_PACK_P7ENCDATA), "PKCS12_pack_p7encdata"}, diff --git a/doc/apps/pkcs12.pod b/doc/apps/pkcs12.pod index 2f2c4d1..e851018 100644 --- a/doc/apps/pkcs12.pod +++ b/doc/apps/pkcs12.pod @@ -325,6 +325,16 @@ encrypted private keys, then the option B<-keypbe PBE-SHA1-RC2-40> can be used to reduce the private key encryption to 40 bit RC2. A complete description of all algorithms is contained in the B<pkcs8> manual page. +Prior 1.1 release passwords containing non-ASCII characters were encoded +in non-compliant manner, which limited interoperability, in first hand +with Windows. But switching to standard-compliant password encoding +poses problem accessing old data protected with broken encoding. For +this reason even legacy encodings is attempted when reading the +data. If you use PKCS#12 files in production application you are advised +to convert the data, because implemented heuristic approach is not +MT-safe, its sole goal is to facilitate the data upgrade with this +utility. + =head1 EXAMPLES Parse a PKCS#12 file and output it to a file: diff --git a/include/openssl/pkcs12.h b/include/openssl/pkcs12.h index 76aa2c4..deaded9 100644 --- a/include/openssl/pkcs12.h +++ b/include/openssl/pkcs12.h @@ -30,19 +30,9 @@ extern "C" { # define PKCS12_SALT_LEN 8 -/* Uncomment out next line for unicode password and names, otherwise ASCII */ - -/* - * #define PBE_UNICODE - */ - -# ifdef PBE_UNICODE -# define PKCS12_key_gen PKCS12_key_gen_uni -# define PKCS12_add_friendlyname PKCS12_add_friendlyname_uni -# else -# define PKCS12_key_gen PKCS12_key_gen_asc -# define PKCS12_add_friendlyname PKCS12_add_friendlyname_asc -# endif +/* It's not clear if these are actually needed... */ +# define PKCS12_key_gen PKCS12_key_gen_utf8 +# define PKCS12_add_friendlyname PKCS12_add_friendlyname_utf8 /* MS key usage constants */ @@ -141,6 +131,8 @@ int PKCS12_add_localkeyid(PKCS12_SAFEBAG *bag, unsigned char *name, int namelen); int PKCS12_add_friendlyname_asc(PKCS12_SAFEBAG *bag, const char *name, int namelen); +int PKCS12_add_friendlyname_utf8(PKCS12_SAFEBAG *bag, const char *name, + int namelen); int PKCS12_add_CSPName_asc(PKCS12_SAFEBAG *bag, const char *name, int namelen); int PKCS12_add_friendlyname_uni(PKCS12_SAFEBAG *bag, @@ -170,6 +162,9 @@ int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt, int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type); +int PKCS12_key_gen_utf8(const char *pass, int passlen, unsigned char *salt, + int saltlen, int id, int iter, int n, + unsigned char *out, const EVP_MD *md_type); int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md_type, int en_de); @@ -183,7 +178,10 @@ int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, int saltlen, const EVP_MD *md_type); unsigned char *OPENSSL_asc2uni(const char *asc, int asclen, unsigned char **uni, int *unilen); -char *OPENSSL_uni2asc(unsigned char *uni, int unilen); +char *OPENSSL_uni2asc(const unsigned char *uni, int unilen); +unsigned char *OPENSSL_utf82uni(const char *asc, int asclen, + unsigned char **uni, int *unilen); +char *OPENSSL_uni2utf8(const unsigned char *uni, int unilen); DECLARE_ASN1_FUNCTIONS(PKCS12) DECLARE_ASN1_FUNCTIONS(PKCS12_MAC_DATA) @@ -237,6 +235,7 @@ int ERR_load_PKCS12_strings(void); # define PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG 117 # define PKCS12_F_PKCS12_KEY_GEN_ASC 110 # define PKCS12_F_PKCS12_KEY_GEN_UNI 111 +# define PKCS12_F_PKCS12_KEY_GEN_UTF8 116 # define PKCS12_F_PKCS12_NEWPASS 128 # define PKCS12_F_PKCS12_PACK_P7DATA 114 # define PKCS12_F_PKCS12_PACK_P7ENCDATA 115 diff --git a/test/recipes/80-test_pkcs12.t b/test/recipes/80-test_pkcs12.t new file mode 100644 index 0000000..bb3e0c8 --- /dev/null +++ b/test/recipes/80-test_pkcs12.t @@ -0,0 +1,42 @@ +use strict; +use warnings; + +use OpenSSL::Test qw/:DEFAULT srctop_file/; +use Encode; + +setup("test_pkcs12"); + +plan tests => 1; + +my $pass = "σύνθημα γνώρισμα"; + +my $savedcp; +if (eval { require Win32::Console; 1; }) { + # Trouble is that Win32 perl uses CreateProcessA, which + # makes it problematic to pass non-ASCII arguments. The only + # feasible option is to pick one language, set corresponding + # code page and reencode the problematic string... + + $savedcp = Win32::Console::OutputCP(); + Win32::Console::OutputCP(1253); + $pass = Encode::encode("cp1253",Encode::decode("utf-8",$pass)); +} else { + # Running MinGW tests transparenly under Wine apparently requires + # UTF-8 locale... + + foreach(`locale -a`) { + s/\R$//; + if ($_ =~ m/^C\.UTF\-?8/i) { + $ENV{LC_ALL} = $_; + last; + } + } +} + +# just see that we can read shibboleth.pfx protected with $pass +ok(run(app(["openssl", "pkcs12", "-noout", + "-password", "pass:$pass", + "-in", srctop_file("test", "shibboleth.pfx")])), + "test_pkcs12"); + +Win32::Console::OutputCP($savedcp) if (defined($savedcp)); diff --git a/test/shibboleth.pfx b/test/shibboleth.pfx new file mode 100644 index 0000000..9c5cc54 Binary files /dev/null and b/test/shibboleth.pfx differ diff --git a/util/libcrypto.num b/util/libcrypto.num index a071a73..78b39c7 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4199,3 +4199,7 @@ X509_get0_notBefore 4145 1_1_0 EXIST::FUNCTION: X509_get0_notAfter 4146 1_1_0 EXIST::FUNCTION: X509_CRL_get0_nextUpdate 4147 1_1_0 EXIST::FUNCTION: BIO_get_new_index 4148 1_1_0 EXIST::FUNCTION: +OPENSSL_utf82uni 4149 1_1_0 EXIST::FUNCTION: +PKCS12_add_friendlyname_utf8 4150 1_1_0 EXIST::FUNCTION: +OPENSSL_uni2utf8 4151 1_1_0 EXIST::FUNCTION: +PKCS12_key_gen_utf8 4152 1_1_0 EXIST::FUNCTION: _____ openssl-commits mailing list To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-commits