summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2003-05-16 18:01:23 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2003-05-16 18:01:23 +0000
commit2742d2131e5deac2e77e9e33c625b6442a6fa1fc (patch)
tree08c28c5da2a8cb50a14bdb7518f8c98fa2cf182f
parent346a6fdcebabeeff7924f800899c05a3c199295e (diff)
downloadgnutls-2742d2131e5deac2e77e9e33c625b6442a6fa1fc.tar.gz
some more stuff about PKCS12. Still on early stage and incomplete.
-rw-r--r--lib/defines.h1
-rw-r--r--lib/minitasn1/decoding.c2
-rw-r--r--lib/minitasn1/element.c12
-rw-r--r--lib/pkix.asn12
-rw-r--r--lib/pkix_asn1_tab.c11
-rw-r--r--lib/x509/pkcs12.c468
-rw-r--r--lib/x509/pkcs12.h11
7 files changed, 493 insertions, 24 deletions
diff --git a/lib/defines.h b/lib/defines.h
index ebb2b8e8d6..4524ade3ca 100644
--- a/lib/defines.h
+++ b/lib/defines.h
@@ -27,6 +27,7 @@
# else
# ifdef _AIX
#pragma alloca
+# endif
# endif
#endif
diff --git a/lib/minitasn1/decoding.c b/lib/minitasn1/decoding.c
index 3b5718b62d..ac3804c7a9 100644
--- a/lib/minitasn1/decoding.c
+++ b/lib/minitasn1/decoding.c
@@ -37,7 +37,7 @@ void
_asn1_error_description_tag_error(node_asn *node,char *ErrorDescription)
{
- Estrcpy(ErrorDescription,":: tag error near element '");
+ Estrcpy(ErrorDescription,":: tag error near element ' ");
_asn1_hierarchical_name(node,ErrorDescription+strlen(ErrorDescription),
MAX_ERROR_DESCRIPTION_SIZE-40);
Estrcat(ErrorDescription,"'");
diff --git a/lib/minitasn1/element.c b/lib/minitasn1/element.c
index 207ff67b4a..004b88b177 100644
--- a/lib/minitasn1/element.c
+++ b/lib/minitasn1/element.c
@@ -35,8 +35,8 @@
void
_asn1_hierarchical_name(node_asn *node,char *name,int name_size)
{
- char *aux;
node_asn *p;
+ char tmp_name[64];
p=node;
@@ -44,16 +44,16 @@ _asn1_hierarchical_name(node_asn *node,char *name,int name_size)
while(p != NULL){
if(p->name != NULL){
- aux=(char*)malloc(strlen(name)+1);
- strcpy(aux,name);
+ _asn1_str_cpy(tmp_name,sizeof(tmp_name),name);
+
_asn1_str_cpy(name,name_size,p->name);
_asn1_str_cat(name,name_size,".");
- _asn1_str_cat(name,name_size,aux);
- free(aux);
+ _asn1_str_cat(name,name_size,tmp_name);
}
p=_asn1_find_up(p);
}
- name[strlen(name)-1]=0;
+
+ if (name[0]==0) _asn1_str_cpy(name,name_size, "ROOT");
}
diff --git a/lib/pkix.asn b/lib/pkix.asn
index 5fec374d6d..62d05de9a3 100644
--- a/lib/pkix.asn
+++ b/lib/pkix.asn
@@ -1111,14 +1111,8 @@ pkcs-12-AuthenticatedSafe ::= SEQUENCE OF pkcs-7-ContentInfo
pkcs-12-SafeContents ::= SEQUENCE OF pkcs-12-SafeBag
--- To replace TYPE-IDENTIFIER
-pkcs-12-BAG-TYPE ::= SEQUENCE {
- type-id OBJECT IDENTIFIER,
- value [0] EXPLICIT ANY DEFINED BY type-id }
-
-
pkcs-12-SafeBag ::= SEQUENCE {
- bagId pkcs-12-BAG-TYPE,
+ bagId OBJECT IDENTIFIER,
bagValue [0] EXPLICIT ANY DEFINED BY badId,
bagAttributes SET OF pkcs-12-PKCS12Attribute OPTIONAL
}
@@ -1142,7 +1136,7 @@ pkcs-12-PKCS8ShroudedKeyBag ::= pkcs-8-EncryptedPrivateKeyInfo
-- CertBag
pkcs-12-CertBag ::= SEQUENCE {
- certId pkcs-12-BAG-TYPE,
+ certId OBJECT IDENTIFIER,
certValue [0] EXPLICIT ANY DEFINED BY certId
}
@@ -1150,7 +1144,7 @@ pkcs-12-CertBag ::= SEQUENCE {
-- DER-encoded X.509 certificate stored in OCTET STRING
pkcs-12-CRLBag ::= SEQUENCE {
- crlId pkcs-12-BAG-TYPE,
+ crlId OBJECT IDENTIFIER,
crlValue [0] EXPLICIT ANY DEFINED BY crlId
}
diff --git a/lib/pkix_asn1_tab.c b/lib/pkix_asn1_tab.c
index 28a4ed0c02..cfe46a72ba 100644
--- a/lib/pkix_asn1_tab.c
+++ b/lib/pkix_asn1_tab.c
@@ -984,13 +984,8 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[]={
{0,2,"pkcs-7-ContentInfo"},
{"pkcs-12-SafeContents",1610612747,0},
{0,2,"pkcs-12-SafeBag"},
- {"pkcs-12-BAG-TYPE",1610612741,0},
- {"type-id",1073741836,0},
- {"value",541073421,0},
- {0,1073743880,"0"},
- {"type-id",1,0},
{"pkcs-12-SafeBag",1610612741,0},
- {"bagId",1073741826,"pkcs-12-BAG-TYPE"},
+ {"bagId",1073741836,0},
{"bagValue",1614815245,0},
{0,1073743880,"0"},
{"badId",1,0},
@@ -1015,12 +1010,12 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[]={
{"pkcs-12-KeyBag",1073741826,"pkcs-8-PrivateKeyInfo"},
{"pkcs-12-PKCS8ShroudedKeyBag",1073741826,"pkcs-8-EncryptedPrivateKeyInfo"},
{"pkcs-12-CertBag",1610612741,0},
- {"certId",1073741826,"pkcs-12-BAG-TYPE"},
+ {"certId",1073741836,0},
{"certValue",541073421,0},
{0,1073743880,"0"},
{"certId",1,0},
{"pkcs-12-CRLBag",1610612741,0},
- {"crlId",1073741826,"pkcs-12-BAG-TYPE"},
+ {"crlId",1073741836,0},
{"crlValue",541073421,0},
{0,1073743880,"0"},
{"crlId",1,0},
diff --git a/lib/x509/pkcs12.c b/lib/x509/pkcs12.c
new file mode 100644
index 0000000000..ce336d1d13
--- /dev/null
+++ b/lib/x509/pkcs12.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2003 Nikos Mavroyanopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Functions that relate on PKCS12 packet parsing.
+ */
+
+#include <libtasn1.h>
+#include <gnutls_int.h>
+
+#ifdef ENABLE_PKI
+
+#include <gnutls_datum.h>
+#include <gnutls_global.h>
+#include <gnutls_errors.h>
+#include <common.h>
+#include <x509_b64.h>
+#include <pkcs12.h>
+#include <dn.h>
+
+#define DATA_OID "1.2.840.113549.1.7.1"
+#define ENC_DATA_OID "1.2.840.113549.1.7.6"
+
+/* Decodes the PKCS #12 auth_safe, and returns the allocated raw data,
+ * which holds them. Returns an ASN1_TYPE of authenticatedSafe.
+ */
+static
+int _decode_pkcs12_auth_safe( ASN1_TYPE pkcs12, ASN1_TYPE * authen_safe, gnutls_datum* raw)
+{
+char oid[128];
+ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+opaque *tmp = NULL;
+int tmp_size, len, result;
+
+ len = sizeof(oid) - 1;
+ result = asn1_read_value(pkcs12, "authSafe.contentType", oid, &len);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ if ( strcmp( oid, DATA_OID) != 0) {
+ gnutls_assert();
+ _gnutls_x509_log( "Unknown PKCS12 Content OID '%s'\n", oid);
+ return GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE;
+ }
+
+
+ tmp_size = 0;
+ result = asn1_read_value(pkcs12, "authSafe.content", NULL, &tmp_size);
+ if (result!=ASN1_MEM_ERROR) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ tmp = gnutls_malloc(tmp_size);
+ if (tmp==NULL) {
+ gnutls_assert();
+ result = GNUTLS_E_MEMORY_ERROR;
+ goto cleanup;
+ }
+
+ result = asn1_read_value(pkcs12, "authSafe.content", tmp, &tmp_size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ /* tmp, tmp_size hold the data and the size of the CertificateSet structure
+ * actually the ANY stuff.
+ */
+
+ /* Step 1. Extract the OCTET STRING.
+ */
+
+ if ((result=asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.pkcs-7-Data", &c2)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_der_decoding(&c2, tmp, tmp_size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_read_value(c2, "", tmp, &tmp_size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ asn1_delete_structure(&c2);
+
+ /* Step 2. Extract the authenticatedSafe.
+ */
+
+ if ((result=asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.pkcs-12-AuthenticatedSafe", &c2)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ result = asn1_der_decoding(&c2, tmp, tmp_size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (raw == NULL) {
+ gnutls_free(tmp);
+ } else {
+ raw->data = tmp;
+ raw->size = tmp_size;
+ }
+
+ *authen_safe = c2;
+
+ return 0;
+
+ cleanup:
+ if (c2) asn1_delete_structure(&c2);
+ gnutls_free(tmp);
+ return result;
+}
+
+/**
+ * gnutls_pkcs12_init - This function initializes a gnutls_pkcs12 structure
+ * @pkcs12: The structure to be initialized
+ *
+ * This function will initialize a PKCS12 structure. PKCS12 structures
+ * usually contain lists of X.509 Certificates and X.509 Certificate
+ * revocation lists.
+ *
+ * Returns 0 on success.
+ *
+ **/
+int gnutls_pkcs12_init(gnutls_pkcs12 * pkcs12)
+{
+ *pkcs12 = gnutls_calloc( 1, sizeof(gnutls_pkcs12_int));
+
+ if (*pkcs12) {
+ int result = asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.pkcs-12-PFX",
+ &(*pkcs12)->pkcs12);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+ return 0; /* success */
+ }
+ return GNUTLS_E_MEMORY_ERROR;
+}
+
+/**
+ * gnutls_pkcs12_deinit - This function deinitializes memory used by a gnutls_pkcs12 structure
+ * @pkcs12: The structure to be initialized
+ *
+ * This function will deinitialize a PKCS12 structure.
+ *
+ **/
+void gnutls_pkcs12_deinit(gnutls_pkcs12 pkcs12)
+{
+ if (pkcs12->pkcs12)
+ asn1_delete_structure(&pkcs12->pkcs12);
+
+ gnutls_free(pkcs12);
+}
+
+/**
+ * gnutls_pkcs12_import - This function will import a DER or PEM encoded PKCS12 structure
+ * @pkcs12: The structure to store the parsed PKCS12.
+ * @data: The DER or PEM encoded PKCS12.
+ * @format: One of DER or PEM
+ * @password: the password that will be used to decrypt the structure
+ * @flags: an ORed sequence of gnutls_privkey_pkcs8_flags
+ *
+ * This function will convert the given DER or PEM encoded PKCS12
+ * to the native gnutls_pkcs12 format. The output will be stored in 'pkcs12'.
+ *
+ * If the PKCS12 is PEM encoded it should have a header of "PKCS12".
+ *
+ * Returns 0 on success.
+ *
+ **/
+int gnutls_pkcs12_import(gnutls_pkcs12 pkcs12, const gnutls_datum * data,
+ gnutls_x509_crt_fmt format, const char* password, unsigned int flags)
+{
+ int result = 0, need_free = 0;
+ gnutls_datum _data = { data->data, data->size };
+
+ /* If the PKCS12 is in PEM format then decode it
+ */
+ if (format == GNUTLS_X509_FMT_PEM) {
+ opaque *out;
+
+ result = _gnutls_fbase64_decode(PEM_PKCS12, data->data, data->size,
+ &out);
+
+ if (result <= 0) {
+ if (result==0) result = GNUTLS_E_INTERNAL_ERROR;
+ gnutls_assert();
+ return result;
+ }
+
+ _data.data = out;
+ _data.size = result;
+
+ need_free = 1;
+ }
+
+ result = asn1_der_decoding(&pkcs12->pkcs12, _data.data, _data.size, NULL);
+ if (result != ASN1_SUCCESS) {
+ result = _gnutls_asn2err(result);
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (need_free) _gnutls_free_datum( &_data);
+
+ return 0;
+
+ cleanup:
+ if (need_free) _gnutls_free_datum( &_data);
+ return result;
+}
+
+
+/**
+ * gnutls_pkcs12_export - This function will export the pkcs12 structure
+ * @pkcs12: Holds the pkcs12 structure
+ * @format: the format of output params. One of PEM or DER.
+ * @output_data: will contain a structure PEM or DER encoded
+ * @output_data_size: holds the size of output_data (and will be replaced by the actual size of parameters)
+ *
+ * This function will export the pkcs12 structure to DER or PEM format.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
+ *
+ * If the structure is PEM encoded, it will have a header
+ * of "BEGIN PKCS12".
+ *
+ * In case of failure a negative value will be returned, and
+ * 0 on success.
+ *
+ **/
+int gnutls_pkcs12_export( gnutls_pkcs12 pkcs12,
+ gnutls_x509_crt_fmt format, unsigned char* output_data, int* output_data_size)
+{
+ return _gnutls_x509_export_int( pkcs12->pkcs12, format, PEM_PKCS12, *output_data_size,
+ output_data, output_data_size);
+}
+
+
+static
+int _parse_safe_contents( ASN1_TYPE sc, const char* sc_name)
+{
+char oid[128];
+ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+opaque *tmp = NULL;
+int tmp_size, len, result;
+
+ tmp_size = 0;
+ result = asn1_read_value(sc, sc_name, NULL, &tmp_size);
+ if (result!=ASN1_MEM_ERROR) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ tmp = gnutls_malloc(tmp_size);
+ if (tmp==NULL) {
+ gnutls_assert();
+ result = GNUTLS_E_MEMORY_ERROR;
+ goto cleanup;
+ }
+
+ result = asn1_read_value(sc, sc_name, tmp, &tmp_size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ /* tmp, tmp_size hold the data and the size of the SafeContents structure
+ * actually the ANY stuff.
+ */
+
+
+ /* Step 1. Extract the OCTET STRING.
+ */
+
+ if ((result=asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.pkcs-7-Data", &c2)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_der_decoding(&c2, tmp, tmp_size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_read_value(c2, "", tmp, &tmp_size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ asn1_delete_structure(&c2);
+
+
+ /* Step 2. Extract the SEQUENCE.
+ */
+
+ if ((result=asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.pkcs-12-SafeContents", &c2)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_der_decoding(&c2, tmp, tmp_size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ gnutls_free(tmp);
+ tmp = NULL;
+
+ len = sizeof(oid);
+ result = asn1_read_value(c2, "?1.bagId", oid, &len);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ asn1_delete_structure(&c2);
+
+fprintf(stderr, "BAG OID: %s\n", oid);
+
+ return 0;
+
+ cleanup:
+ if (c2) asn1_delete_structure(&c2);
+ gnutls_free(tmp);
+ return result;
+}
+
+
+/* FIXME: This is not a proper API. PKCS 12 packets are too complex to
+ * handle like this. A proper API has to be designed.
+ */
+
+/**
+ * gnutls_pkcs12_get_certificate - This function returns a certificate in a PKCS12 structure
+ * @pkcs12_struct: should contain a gnutls_pkcs12 structure
+ * @indx: contains the index of the certificate to extract
+ * @certificate: the contents of the certificate will be copied there (may be null)
+ * @certificate_size: should hold the size of the certificate
+ *
+ * This function will return an (X.509) certificate of the PKCS12 structure.
+ * Returns 0 on success. If the provided buffer is not long enough,
+ * then GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
+ *
+ * After the last certificate has been read GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * will be returned.
+ *
+ **/
+int gnutls_pkcs12_get_certificate(gnutls_pkcs12 pkcs12,
+ int indx, unsigned char* certificate, int* certificate_size)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int result, len;
+ char root2[64];
+ char oid[128];
+ char counter[MAX_INT_DIGITS];
+ gnutls_datum tmp = {NULL, 0};
+
+ if (certificate_size == NULL) return GNUTLS_E_INVALID_REQUEST;
+
+ /* Step 1. decode the data.
+ */
+ result = _decode_pkcs12_auth_safe( pkcs12->pkcs12, &c2, NULL);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ /* Step 2. Parse the AuthenticatedSafe
+ */
+
+ _gnutls_str_cpy( root2, sizeof(root2), "?");
+ _gnutls_int2str( indx+1, counter);
+ _gnutls_str_cat( root2, sizeof(root2), counter);
+ _gnutls_str_cat( root2, sizeof(root2), ".contentType");
+
+ len = sizeof(oid) - 1;
+
+ result = asn1_read_value(c2, root2, oid, &len);
+
+ if (result == ASN1_VALUE_NOT_FOUND) {
+ result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ goto cleanup;
+ }
+
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ /* Not encrypted Bag
+ */
+ if (strcmp( oid, DATA_OID) == 0) {
+ _gnutls_str_cpy( root2, sizeof(root2), "?");
+ _gnutls_int2str( indx+1, counter);
+ _gnutls_str_cat( root2, sizeof(root2), counter);
+ _gnutls_str_cat( root2, sizeof(root2), ".content");
+
+ result = _parse_safe_contents( c2, root2);
+ goto cleanup;
+ }
+
+ /* ENC_DATA_OID needs decryption */
+fprintf(stderr, "OID: %s\n", oid);
+
+return GNUTLS_E_MEMORY_ERROR;
+
+ cleanup:
+ _gnutls_free_datum( &tmp);
+ if (c2) asn1_delete_structure(&c2);
+ return result;
+}
+
+
+#endif /* ENABLE_PKI */
diff --git a/lib/x509/pkcs12.h b/lib/x509/pkcs12.h
new file mode 100644
index 0000000000..a8ecefd5f9
--- /dev/null
+++ b/lib/x509/pkcs12.h
@@ -0,0 +1,11 @@
+
+typedef struct gnutls_pkcs12_int {
+ ASN1_TYPE pkcs12;
+} gnutls_pkcs12_int;
+
+typedef struct gnutls_pkcs12_int *gnutls_pkcs12;
+
+int gnutls_pkcs12_init(gnutls_pkcs12 * pkcs12);
+void gnutls_pkcs12_deinit(gnutls_pkcs12 pkcs12);
+int gnutls_pkcs12_import(gnutls_pkcs12 pkcs12, const gnutls_datum * data,
+ gnutls_x509_crt_fmt format, const char* password, unsigned int flags);