Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Langley <agl@google.com>2014-09-19 21:49:56 +0400
committerAdam Langley <agl@google.com>2014-09-20 04:10:03 +0400
commit5127db3b4d59066126a1f8c8f7fdf4841a8c58b9 (patch)
tree7a31618dc3251d389cba75d20b71bafc52b3d307 /crypto/pkcs8
parent588d2528d1e9e7d1c076563e47ecbfabc6e49cb1 (diff)
Provide compatibility functions for PKCS#12 parsing.
In order to minimise the upstream diffs needed for bits of Android to build with BoringSSL, this change implements the old style PKCS#12 functions as wrappers around the modern parser. The function to read all the contents of a BIO could almost be a utility function but I'll wait until there are two uses for it first. The important change from the original functions is that these will always read the complete buffer/BIO/FILE passed in. Based on a survey of uses of d2i_PKCS12 that I found, this appears to be universally what callers want anyway. Change-Id: I3f5b84e710b161d975f91f4d16c83d44371368d1 Reviewed-on: https://boringssl-review.googlesource.com/1791 Reviewed-by: Adam Langley <agl@google.com>
Diffstat (limited to 'crypto/pkcs8')
-rw-r--r--crypto/pkcs8/pkcs12_test.c45
-rw-r--r--crypto/pkcs8/pkcs8.c139
2 files changed, 181 insertions, 3 deletions
diff --git a/crypto/pkcs8/pkcs12_test.c b/crypto/pkcs8/pkcs12_test.c
index 6aea1ebc..2292b778 100644
--- a/crypto/pkcs8/pkcs12_test.c
+++ b/crypto/pkcs8/pkcs12_test.c
@@ -705,13 +705,56 @@ static int test(const char *name, const uint8_t *der, size_t der_len) {
return 1;
}
+static int test_compat(const uint8_t *der, size_t der_len) {
+ PKCS12 *p12;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca_certs = NULL;
+ EVP_PKEY *key;
+ BIO *bio;
+
+ bio = BIO_new_mem_buf((void*) der, der_len);
+
+ p12 = d2i_PKCS12_bio(bio, NULL);
+ if (p12 == NULL) {
+ fprintf(stderr, "PKCS12_parse failed.\n");
+ BIO_print_errors_fp(stderr);
+ return 0;
+ }
+ BIO_free(bio);
+
+ if (!PKCS12_parse(p12, "foo", &key, &cert, &ca_certs)) {
+ fprintf(stderr, "PKCS12_parse failed.\n");
+ BIO_print_errors_fp(stderr);
+ return 0;
+ }
+
+ if (key == NULL || cert == NULL) {
+ fprintf(stderr, "Bad result from PKCS12_parse.\n");
+ return 0;
+ }
+
+ EVP_PKEY_free(key);
+ X509_free(cert);
+
+ if (sk_X509_num(ca_certs) != 0) {
+ fprintf(stderr, "Bad result from PKCS12_parse.\n");
+ return 0;
+ }
+ sk_X509_free(ca_certs);
+
+ PKCS12_free(p12);
+
+ return 1;
+}
+
int main(int argc, char **argv) {
CRYPTO_library_init();
ERR_load_crypto_strings();
if (!test("OpenSSL", kOpenSSL, sizeof(kOpenSSL)) ||
!test("NSS", kNSS, sizeof(kNSS)) ||
- !test("Windows", kWindows, sizeof(kWindows))) {
+ !test("Windows", kWindows, sizeof(kWindows)) ||
+ !test_compat(kWindows, sizeof(kWindows))) {
return 1;
}
diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c
index 915767e7..58e400dd 100644
--- a/crypto/pkcs8/pkcs8.c
+++ b/crypto/pkcs8/pkcs8.c
@@ -55,8 +55,12 @@
#include <openssl/pkcs8.h>
+#include <assert.h>
+#include <limits.h>
+
#include <openssl/asn1.h>
#include <openssl/bn.h>
+#include <openssl/buf.h>
#include <openssl/cipher.h>
#include <openssl/digest.h>
#include <openssl/err.h>
@@ -64,8 +68,6 @@
#include <openssl/mem.h>
#include <openssl/x509.h>
-#include <limits.h>
-
#include "../bytestring/internal.h"
#include "../evp/internal.h"
@@ -879,6 +881,7 @@ int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs,
/* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section
* four. */
if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) ||
+ CBS_len(&in) != 0 ||
!CBS_get_asn1_uint64(&pfx, &version)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
goto err;
@@ -1017,3 +1020,135 @@ err:
}
void PKCS12_PBE_add(){};
+
+struct pkcs12_st {
+ uint8_t *ber_bytes;
+ size_t ber_len;
+};
+
+PKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) {
+ PKCS12 *p12;
+
+ /* out_p12 must be NULL because we don't export the PKCS12 structure. */
+ assert(out_p12 == NULL);
+
+ p12 = OPENSSL_malloc(sizeof(PKCS12));
+ if (!p12) {
+ return NULL;
+ }
+
+ p12->ber_bytes = OPENSSL_malloc(ber_len);
+ if (!p12->ber_bytes) {
+ OPENSSL_free(p12);
+ return NULL;
+ }
+
+ memcpy(p12->ber_bytes, *ber_bytes, ber_len);
+ p12->ber_len = ber_len;
+ *ber_bytes += ber_len;
+
+ return p12;
+}
+
+PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12) {
+ size_t used = 0;
+ BUF_MEM *buf;
+ const uint8_t *dummy;
+ static const size_t kMaxSize = 256 * 1024;
+ PKCS12 *ret = NULL;
+
+ buf = BUF_MEM_new();
+ if (buf == NULL) {
+ return NULL;
+ }
+ if (BUF_MEM_grow(buf, 8192) == 0) {
+ goto out;
+ }
+
+ for (;;) {
+ int n = BIO_read(bio, &buf->data[used], buf->length - used);
+ if (n < 0) {
+ goto out;
+ }
+
+ if (n == 0) {
+ break;
+ }
+ used += n;
+
+ if (used < buf->length) {
+ continue;
+ }
+
+ if (buf->length > kMaxSize ||
+ BUF_MEM_grow(buf, buf->length * 2) == 0) {
+ goto out;
+ }
+ }
+
+ dummy = (uint8_t*) buf->data;
+ ret = d2i_PKCS12(out_p12, &dummy, used);
+
+out:
+ BUF_MEM_free(buf);
+ return ret;
+}
+
+PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12) {
+ BIO *bio;
+ PKCS12 *ret;
+
+ bio = BIO_new_fp(fp, 0 /* don't take ownership */);
+ if (!bio) {
+ return NULL;
+ }
+
+ ret = d2i_PKCS12_bio(bio, out_p12);
+ BIO_free(bio);
+ return ret;
+}
+
+int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey,
+ X509 **out_cert, STACK_OF(X509) **out_ca_certs) {
+ CBS ber_bytes;
+ STACK_OF(X509) *ca_certs = NULL;
+ char ca_certs_alloced = 0;
+
+ if (out_ca_certs != NULL && *out_ca_certs != NULL) {
+ ca_certs = *out_ca_certs;
+ }
+
+ if (!ca_certs) {
+ ca_certs = sk_X509_new_null();
+ if (ca_certs == NULL) {
+ return 0;
+ }
+ ca_certs_alloced = 1;
+ }
+
+ CBS_init(&ber_bytes, p12->ber_bytes, p12->ber_len);
+ if (!PKCS12_get_key_and_certs(out_pkey, ca_certs, &ber_bytes, password)) {
+ if (ca_certs_alloced) {
+ sk_X509_free(ca_certs);
+ }
+ return 0;
+ }
+
+ *out_cert = NULL;
+ if (sk_X509_num(ca_certs) > 0) {
+ *out_cert = sk_X509_shift(ca_certs);
+ }
+
+ if (out_ca_certs) {
+ *out_ca_certs = ca_certs;
+ } else {
+ sk_X509_pop_free(ca_certs, X509_free);
+ }
+
+ return 1;
+}
+
+void PKCS12_free(PKCS12 *p12) {
+ OPENSSL_free(p12->ber_bytes);
+ OPENSSL_free(p12);
+}