From: Richard Levitte Date: Fri, 12 Oct 2018 14:56:44 +0000 (+0200) Subject: OSSL_STORE: Make the 'file' scheme loader handle MSBLOB and PVK files X-Git-Tag: openssl-3.0.0-alpha2~37 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=f55838f34dd5c65420662f7eacf6c6ffd7f261a2 OSSL_STORE: Make the 'file' scheme loader handle MSBLOB and PVK files This involves exposing two pvkfmt.c functions, but only internally. Reviewed-by: David von Oheimb (Merged from https://github.com/openssl/openssl/pull/11756) --- diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 8449ecea74..9fa051f5c3 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1000,12 +1000,12 @@ PEM_F_D2I_PKCS8PRIVATEKEY_BIO:120:d2i_PKCS8PrivateKey_bio PEM_F_D2I_PKCS8PRIVATEKEY_FP:121:d2i_PKCS8PrivateKey_fp PEM_F_DO_B2I:132:do_b2i PEM_F_DO_B2I_BIO:133:do_b2i_bio -PEM_F_DO_BLOB_HEADER:134:do_blob_header +PEM_F_OSSL_DO_BLOB_HEADER:134:ossl_do_blob_header PEM_F_DO_I2B:146:do_i2b PEM_F_DO_PK8PKEY:126:do_pk8pkey PEM_F_DO_PK8PKEY_FP:125:do_pk8pkey_fp PEM_F_DO_PVK_BODY:135:do_PVK_body -PEM_F_DO_PVK_HEADER:136:do_PVK_header +PEM_F_OSSL_DO_PVK_HEADER:136:ossl_do_PVK_header PEM_F_GET_HEADER_AND_DATA:143:get_header_and_data PEM_F_GET_NAME:144:get_name PEM_F_I2B_PVK:137:i2b_PVK diff --git a/crypto/include/internal/pem_int.h b/crypto/include/internal/pem_int.h new file mode 100644 index 0000000000..e065ac75a5 --- /dev/null +++ b/crypto/include/internal/pem_int.h @@ -0,0 +1,23 @@ +/* + * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_PEM_INT_H +# define HEADER_PEM_INT_H + +# include + +/* Found in crypto/pem/pvkfmt.c */ +int ossl_do_blob_header(const unsigned char **in, unsigned int length, + unsigned int *pmagic, unsigned int *pbitlen, + int *pisdss, int *pispub); +int ossl_do_PVK_header(const unsigned char **in, unsigned int length, + int skip_magic, + unsigned int *psaltlen, unsigned int *pkeylen); + +#endif diff --git a/crypto/pem/pvkfmt.c b/crypto/pem/pvkfmt.c index 1a24ce755a..e2f5702880 100644 --- a/crypto/pem/pvkfmt.c +++ b/crypto/pem/pvkfmt.c @@ -20,6 +20,7 @@ #include "internal/cryptlib.h" #include +#include "internal/pem_int.h" #include #include #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) @@ -89,9 +90,9 @@ static EVP_PKEY *b2i_rsa(const unsigned char **in, static EVP_PKEY *b2i_dss(const unsigned char **in, unsigned int bitlen, int ispub); -static int do_blob_header(const unsigned char **in, unsigned int length, - unsigned int *pmagic, unsigned int *pbitlen, - int *pisdss, int *pispub) +int ossl_do_blob_header(const unsigned char **in, unsigned int length, + unsigned int *pmagic, unsigned int *pbitlen, + int *pisdss, int *pispub) { const unsigned char *p = *in; if (length < 16) @@ -99,13 +100,13 @@ static int do_blob_header(const unsigned char **in, unsigned int length, /* bType */ if (*p == MS_PUBLICKEYBLOB) { if (*pispub == 0) { - PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB); + PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB); return 0; } *pispub = 1; } else if (*p == MS_PRIVATEKEYBLOB) { if (*pispub == 1) { - PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB); + PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB); return 0; } *pispub = 0; @@ -114,7 +115,7 @@ static int do_blob_header(const unsigned char **in, unsigned int length, p++; /* Version */ if (*p++ != 0x2) { - PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_VERSION_NUMBER); + PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_BAD_VERSION_NUMBER); return 0; } /* Ignore reserved, aiKeyAlg */ @@ -129,7 +130,7 @@ static int do_blob_header(const unsigned char **in, unsigned int length, /* fall thru */ case MS_RSA1MAGIC: if (*pispub == 0) { - PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB); + PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB); return 0; } break; @@ -139,13 +140,13 @@ static int do_blob_header(const unsigned char **in, unsigned int length, /* fall thru */ case MS_RSA2MAGIC: if (*pispub == 1) { - PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB); + PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB); return 0; } break; default: - PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_MAGIC_NUMBER); + PEMerr(PEM_F_OSSL_DO_BLOB_HEADER, PEM_R_BAD_MAGIC_NUMBER); return -1; } *in = p; @@ -191,7 +192,7 @@ static EVP_PKEY *do_b2i(const unsigned char **in, unsigned int length, const unsigned char *p = *in; unsigned int bitlen, magic; int isdss; - if (do_blob_header(&p, length, &magic, &bitlen, &isdss, &ispub) <= 0) { + if (ossl_do_blob_header(&p, length, &magic, &bitlen, &isdss, &ispub) <= 0) { PEMerr(PEM_F_DO_B2I, PEM_R_KEYBLOB_HEADER_PARSE_ERROR); return NULL; } @@ -218,7 +219,7 @@ static EVP_PKEY *do_b2i_bio(BIO *in, int ispub) return NULL; } p = hdr_buf; - if (do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0) + if (ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0) return NULL; length = blob_length(bitlen, isdss, ispub); @@ -617,26 +618,26 @@ int i2b_PublicKey_bio(BIO *out, const EVP_PKEY *pk) # ifndef OPENSSL_NO_RC4 -static int do_PVK_header(const unsigned char **in, unsigned int length, - int skip_magic, - unsigned int *psaltlen, unsigned int *pkeylen) +int ossl_do_PVK_header(const unsigned char **in, unsigned int length, + int skip_magic, + unsigned int *psaltlen, unsigned int *pkeylen) { const unsigned char *p = *in; unsigned int pvk_magic, is_encrypted; if (skip_magic) { if (length < 20) { - PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT); + PEMerr(PEM_F_OSSL_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT); return 0; } } else { if (length < 24) { - PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT); + PEMerr(PEM_F_OSSL_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT); return 0; } pvk_magic = read_ledword(&p); if (pvk_magic != MS_PVKMAGIC) { - PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_BAD_MAGIC_NUMBER); + PEMerr(PEM_F_OSSL_DO_PVK_HEADER, PEM_R_BAD_MAGIC_NUMBER); return 0; } } @@ -653,7 +654,7 @@ static int do_PVK_header(const unsigned char **in, unsigned int length, return 0; if (is_encrypted && *psaltlen == 0) { - PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_INCONSISTENT_HEADER); + PEMerr(PEM_F_OSSL_DO_PVK_HEADER, PEM_R_INCONSISTENT_HEADER); return 0; } @@ -766,7 +767,7 @@ EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u) } p = pvk_hdr; - if (!do_PVK_header(&p, 24, 0, &saltlen, &keylen)) + if (!ossl_do_PVK_header(&p, 24, 0, &saltlen, &keylen)) return 0; buflen = (int)keylen + saltlen; buf = OPENSSL_malloc(buflen); diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c index 05938a27c8..9f6158ff79 100644 --- a/crypto/store/loader_file.c +++ b/crypto/store/loader_file.c @@ -18,6 +18,7 @@ #include #include #include +#include "internal/pem_int.h" #include /* For the PKCS8 stuff o.O */ #include /* For d2i_RSAPrivateKey */ #include @@ -1181,6 +1182,84 @@ static int file_read_pem(BIO *bp, char **pem_name, char **pem_header, return 1; } +static OSSL_STORE_INFO *file_try_read_msblob(BIO *bp, int *matchcount) +{ +#ifdef OPENSSL_NO_DSA + return NULL; +#else + OSSL_STORE_INFO *result = NULL; + int ispub = -1; + + { + unsigned int magic = 0, bitlen = 0; + int isdss = 0; + unsigned char peekbuf[16] = { 0, }; + const unsigned char *p = peekbuf; + + if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0) + return 0; + if (!ossl_do_blob_header(&p, sizeof(peekbuf), &magic, &bitlen, + &isdss, &ispub)) + return 0; + } + + (*matchcount)++; + + { + EVP_PKEY *tmp = ispub + ? b2i_PublicKey_bio(bp) + : b2i_PrivateKey_bio(bp); + + if (tmp == NULL + || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) { + EVP_PKEY_free(tmp); + return 0; + } + } + + return result; +#endif +} + +static OSSL_STORE_INFO *file_try_read_PVK(BIO *bp, const UI_METHOD *ui_method, + void *ui_data, const char *uri, + int *matchcount) +{ +#if defined(OPENSSL_NO_DSA) || defined(OPENSSL_NO_RC4) + return NULL; +#else + OSSL_STORE_INFO *result = NULL; + + { + unsigned int saltlen = 0, keylen = 0; + unsigned char peekbuf[24] = { 0, }; + const unsigned char *p = peekbuf; + + if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0) + return 0; + if (!ossl_do_PVK_header(&p, sizeof(peekbuf), 0, &saltlen, &keylen)) + return 0; + } + + (*matchcount)++; + + { + EVP_PKEY *tmp = NULL; + struct pem_pass_data pass_data; + + if (!file_fill_pem_pass_data(&pass_data, "PVK pass phrase", uri, + ui_method, ui_data) + || (tmp = b2i_PVK_bio(bp, file_get_pem_pass, &pass_data)) == NULL + || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) { + EVP_PKEY_free(tmp); + return 0; + } + } + + return result; +#endif +} + static int file_read_asn1(BIO *bp, unsigned char **data, long *len) { BUF_MEM *mem = NULL; @@ -1370,6 +1449,13 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, goto endloop; } } else { + if ((result = file_try_read_msblob(ctx->_.file.file, + &matchcount)) != NULL + || (result = file_try_read_PVK(ctx->_.file.file, + ui_method, ui_data, ctx->uri, + &matchcount)) != NULL) + goto endloop; + if (!file_read_asn1(ctx->_.file.file, &data, &len)) { ctx->errcnt++; goto endloop;