diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-05-16 18:01:23 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-05-16 18:01:23 +0000 |
commit | 2742d2131e5deac2e77e9e33c625b6442a6fa1fc (patch) | |
tree | 08c28c5da2a8cb50a14bdb7518f8c98fa2cf182f | |
parent | 346a6fdcebabeeff7924f800899c05a3c199295e (diff) | |
download | gnutls-2742d2131e5deac2e77e9e33c625b6442a6fa1fc.tar.gz |
some more stuff about PKCS12. Still on early stage and incomplete.
-rw-r--r-- | lib/defines.h | 1 | ||||
-rw-r--r-- | lib/minitasn1/decoding.c | 2 | ||||
-rw-r--r-- | lib/minitasn1/element.c | 12 | ||||
-rw-r--r-- | lib/pkix.asn | 12 | ||||
-rw-r--r-- | lib/pkix_asn1_tab.c | 11 | ||||
-rw-r--r-- | lib/x509/pkcs12.c | 468 | ||||
-rw-r--r-- | lib/x509/pkcs12.h | 11 |
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); |