summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2003-03-26 13:42:22 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2003-03-26 13:42:22 +0000
commitce66a574ff9bb7869b083ccea2adca1a1fd611b7 (patch)
tree36597818859bde1ba0101d927cfbad5c38f60bd4 /lib
parent4bc984a3b066550977bd7ad9080a175ff0e81625 (diff)
downloadgnutls-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.c1
-rw-r--r--lib/gnutls_errors_int.h1
-rw-r--r--lib/x509/pkcs7.c281
-rw-r--r--lib/x509/privkey_pkcs8.c10
-rw-r--r--lib/x509/x509.c2
-rw-r--r--lib/x509/x509.h3
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;