diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-03-26 13:42:22 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-03-26 13:42:22 +0000 |
commit | ce66a574ff9bb7869b083ccea2adca1a1fd611b7 (patch) | |
tree | 36597818859bde1ba0101d927cfbad5c38f60bd4 /lib | |
parent | 4bc984a3b066550977bd7ad9080a175ff0e81625 (diff) | |
download | gnutls-ce66a574ff9bb7869b083ccea2adca1a1fd611b7.tar.gz |
Added functionality to generate PKCS #7 structures. Currently only certificates
can be put there. (untested)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gnutls_errors.c | 1 | ||||
-rw-r--r-- | lib/gnutls_errors_int.h | 1 | ||||
-rw-r--r-- | lib/x509/pkcs7.c | 281 | ||||
-rw-r--r-- | lib/x509/privkey_pkcs8.c | 10 | ||||
-rw-r--r-- | lib/x509/x509.c | 2 | ||||
-rw-r--r-- | lib/x509/x509.h | 3 |
6 files changed, 288 insertions, 10 deletions
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index b871f851e8..4ff2a93f56 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -134,6 +134,7 @@ static gnutls_error_entry error_algorithms[] = { ERROR_ENTRY("The OpenPGP fingerprint is not supported.", GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED, 1), ERROR_ENTRY("The certificate has unsupported attributes.", GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE, 1), ERROR_ENTRY("The hash algorithm is unknown.", GNUTLS_E_UNKNOWN_HASH_ALGORITHM, 1), + ERROR_ENTRY("The PKCS7 structure's content type is unknown.", GNUTLS_E_UNKNOWN_PKCS7_CONTENT_TYPE, 1), {0, 0, 0, 0} }; diff --git a/lib/gnutls_errors_int.h b/lib/gnutls_errors_int.h index 30aa175b9c..51552af11f 100644 --- a/lib/gnutls_errors_int.h +++ b/lib/gnutls_errors_int.h @@ -110,6 +110,7 @@ #define GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED -94 #define GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE -95 #define GNUTLS_E_UNKNOWN_HASH_ALGORITHM -96 +#define GNUTLS_E_UNKNOWN_PKCS7_CONTENT_TYPE -97 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -250 diff --git a/lib/x509/pkcs7.c b/lib/x509/pkcs7.c index 4bf30284ef..36e1253682 100644 --- a/lib/x509/pkcs7.c +++ b/lib/x509/pkcs7.c @@ -32,6 +32,8 @@ #include <pkcs7.h> #include <dn.h> +#define SIGNED_DATA_OID "1.2.840.113549.1.7.2" + /** * gnutls_pkcs7_init - This function initializes a gnutls_pkcs7 structure * @pkcs7: The structure to be initialized @@ -168,7 +170,9 @@ int gnutls_pkcs7_get_certificate(gnutls_pkcs7 pkcs7, return _gnutls_asn2err(result); } - if ( strcmp( oid, "1.2.840.113549.1.7.2") != 0) { + /* id-signedData as defined in PKCS #7 + */ + if ( strcmp( oid, SIGNED_DATA_OID) != 0) { gnutls_assert(); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } @@ -212,7 +216,7 @@ int gnutls_pkcs7_get_certificate(gnutls_pkcs7 pkcs7, result = _gnutls_asn2err(result); goto cleanup; } - + /* Step 2. Parse the CertificateSet */ @@ -303,7 +307,7 @@ int gnutls_pkcs7_get_certificate_count(gnutls_pkcs7 pkcs7) return _gnutls_asn2err(result); } - if ( strcmp( oid, "1.2.840.113549.1.7.2") != 0) { + if ( strcmp( oid, SIGNED_DATA_OID) != 0) { gnutls_assert(); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } @@ -352,6 +356,7 @@ int gnutls_pkcs7_get_certificate_count(gnutls_pkcs7 pkcs7) } gnutls_free(tmp); + tmp = NULL; /* Step 2. Count the CertificateSet */ @@ -371,3 +376,273 @@ int gnutls_pkcs7_get_certificate_count(gnutls_pkcs7 pkcs7) return result; } +/** + * gnutls_pkcs7_export - This function will export the pkcs7 structure + * @pkcs7: Holds the pkcs7 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 pkcs7 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 CERTIFICATE". + * + * In case of failure a negative value will be returned, and + * 0 on success. + * + **/ +int gnutls_pkcs7_export( gnutls_pkcs7 pkcs7, + gnutls_x509_crt_fmt format, unsigned char* output_data, int* output_data_size) +{ + return _gnutls_x509_export_int( pkcs7->pkcs7, format, PEM_PKCS7, *output_data_size, + output_data, output_data_size); +} + + +static int create_empty_signed_data(ASN1_TYPE pkcs7) +{ + ASN1_TYPE c2 = ASN1_TYPE_EMPTY, ec = ASN1_TYPE_EMPTY; + uint8 one = 1; + int result; + + if ((result=asn1_create_element + (_gnutls_get_pkix(), "PKIX1.SignedData", &c2)) != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Use version 1 + */ + result = asn1_write_value( c2, "version", &one, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Use no digest algorithms + */ + result = asn1_write_value( c2, "digestAlgorithms", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Create a data encapContentInfo + */ + if ((result=asn1_create_element + (_gnutls_get_pkix(), "PKIX1.EncapsulatedContentInfo", &ec)) != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* id-data */ + result = asn1_write_value( ec, "eContentType", "1.2.840.113549.1.7.5", 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value( ec, "eContent", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Copy the generated encapsulated data. + */ + result = _gnutls_x509_der_encode_and_copy( ec, "", c2, "encapContentInfo"); + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + asn1_delete_structure( &ec); + + + /* Add no certificates. + */ + result = asn1_write_value( c2, "certificates", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Add no crls. + */ + result = asn1_write_value( c2, "crls", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Add no signerInfos. + */ + result = asn1_write_value( c2, "signerInfos", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Copy the signed data to the pkcs7 + */ + result = _gnutls_x509_der_encode_and_copy( c2, "", pkcs7, "content"); + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + asn1_delete_structure( &c2); + + /* Write the content type of the signed data + */ + result = asn1_write_value(pkcs7, "contentType", SIGNED_DATA_OID, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + return 0; + + cleanup: + asn1_delete_structure( &c2); + asn1_delete_structure( &ec); + return result; + +} + +/** + * gnutls_pkcs7_set_certificate - This function adds a certificate in a PKCS7 certificate set + * @pkcs7_struct: should contain a gnutls_pkcs7 structure + * @crt: the DER encoded certificate to be added + * + * This function will add a certificate to the PKCS7 or RFC2630 certificate set. + * Returns 0 on success. + * + **/ +int gnutls_pkcs7_set_certificate(gnutls_pkcs7 pkcs7, + const gnutls_datum* crt) +{ + ASN1_TYPE c2 = ASN1_TYPE_EMPTY; + int result, len; + char oid[128]; + opaque *tmp = NULL; + int tmp_size; + + /* root2 is used as a temp storage area + */ + len = sizeof(oid) - 1; + result = asn1_read_value(pkcs7->pkcs7, "contentType", oid, &len); + if (result != ASN1_VALUE_NOT_FOUND && result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + if ( strcmp( oid, SIGNED_DATA_OID) != 0) { + gnutls_assert(); + return GNUTLS_E_UNKNOWN_PKCS7_CONTENT_TYPE; + } + + if (result == ASN1_VALUE_NOT_FOUND) { + /* The pkcs7 structure is new, so create the + * signedData. + */ + result = create_empty_signed_data( pkcs7->pkcs7); + if (result < 0) { + gnutls_assert(); + return result; + } + } + + if ((result=asn1_create_element + (_gnutls_get_pkix(), "PKIX1.SignedData", &c2)) != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* the Signed-data has been created, so + * decode them. + */ + tmp_size = 0; + result = asn1_read_value(pkcs7->pkcs7, "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(pkcs7->pkcs7, "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. In case of a signed structure extract certificate set. + */ + + result = asn1_der_decoding(&c2, tmp, tmp_size, NULL); + if (result != ASN1_SUCCESS) { + /* couldn't decode DER */ + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + gnutls_free(tmp); + tmp = NULL; + + /* Step 2. Append the new certificate. + */ + result = asn1_write_value(c2, "certificates.?LAST", "certificate", 1); + if (result != ASN1_SUCCESS) { + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value(c2, "certificates.?LAST.certificate", crt->data, crt->size); + if (result != ASN1_SUCCESS) { + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Step 3. Replace the old content with the new + */ + result = _gnutls_x509_der_encode_and_copy( c2, "", pkcs7->pkcs7, "content"); + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + + asn1_delete_structure(&c2); + + return 0; + + cleanup: + if (c2) asn1_delete_structure(&c2); + gnutls_free(tmp); + return result; +} diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c index 0ea0d4e65a..019a502ccc 100644 --- a/lib/x509/privkey_pkcs8.c +++ b/lib/x509/privkey_pkcs8.c @@ -68,8 +68,6 @@ static int decrypt_data( ASN1_TYPE pkcs8_asn, char* password, static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_privkey pkey); static int write_pbe2_params( ASN1_TYPE pkcs8_asn, const struct pbkdf2_params* kdf_params, const struct pbe_enc_params* enc_params); -static int _der_encode_and_copy( ASN1_TYPE src, const char* src_name, - ASN1_TYPE dest, const char* dest_name); static int encrypt_data( const gnutls_datum* plain, const struct pbe_enc_params *enc_params, gnutls_datum* key, gnutls_datum* encrypted); @@ -901,7 +899,7 @@ int key_size; * dest in dest_name. Usefull to encode something and store it * as OCTET. */ -static int _der_encode_and_copy( ASN1_TYPE src, const char* src_name, +int _gnutls_x509_der_encode_and_copy( ASN1_TYPE src, const char* src_name, ASN1_TYPE dest, const char* dest_name) { int size, result; @@ -1019,7 +1017,7 @@ char tmp[64]; /* now encode them an put the DER output * in the keyDerivationFunc.parameters */ - result = _der_encode_and_copy( pbkdf2_asn, "", + result = _gnutls_x509_der_encode_and_copy( pbkdf2_asn, "", pbes2_asn, "keyDerivationFunc.parameters"); if (result < 0) { gnutls_assert(); @@ -1070,7 +1068,7 @@ ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY; /* now encode them an put the DER output * in the encryptionScheme.parameters */ - result = _der_encode_and_copy( pbe_asn, "", + result = _gnutls_x509_der_encode_and_copy( pbe_asn, "", pbes2_asn, "encryptionScheme.parameters"); if (result < 0) { gnutls_assert(); @@ -1159,7 +1157,7 @@ ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY; goto error; } - result = _der_encode_and_copy( pbes2_asn, "", + result = _gnutls_x509_der_encode_and_copy( pbes2_asn, "", pkcs8_asn, "encryptionAlgorithm.parameters"); if (result < 0) { gnutls_assert(); diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 7a8dcf3910..8ef97bcffa 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -1068,7 +1068,7 @@ gnutls_datum tmp; * gnutls_x509_crt_export - This function will export the certificate * @cert: Holds the certificate * @format: the format of output params. One of PEM or DER. - * @output_data: will contain a private key PEM or DER encoded + * @output_data: will contain a certificate 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 certificate to DER or PEM format. diff --git a/lib/x509/x509.h b/lib/x509/x509.h index ee066a0c3d..149767f885 100644 --- a/lib/x509/x509.h +++ b/lib/x509/x509.h @@ -64,6 +64,9 @@ typedef struct gnutls_x509_privkey_int { ASN1_TYPE key; } gnutls_x509_privkey_int; +int _gnutls_x509_der_encode_and_copy( ASN1_TYPE src, const char* src_name, + ASN1_TYPE dest, const char* dest_name); + typedef struct gnutls_x509_crt_int *gnutls_x509_crt; typedef struct gnutls_x509_crl_int *gnutls_x509_crl; typedef struct gnutls_x509_privkey_int *gnutls_x509_privkey; |