Migrated scepclient to new modular PKCS# API
authorMartin Willi <martin@revosec.ch>
Wed, 28 Nov 2012 11:41:38 +0000 (12:41 +0100)
committerMartin Willi <martin@revosec.ch>
Wed, 19 Dec 2012 09:32:08 +0000 (10:32 +0100)
src/scepclient/scep.c
src/scepclient/scep.h
src/scepclient/scepclient.c

index f7a1f0b..faaac88 100644 (file)
@@ -68,13 +68,12 @@ const scep_attributes_t empty_scep_attributes = {
 /**
  * Extract X.501 attributes
  */
-void extract_attributes(pkcs7_t *pkcs7, scep_attributes_t *attrs)
+void extract_attributes(pkcs7_t *pkcs7, enumerator_t *enumerator,
+                                               scep_attributes_t *attrs)
 {
-       pkcs9_t *attributes = pkcs7->get_attributes(pkcs7);
        chunk_t attr;
 
-       attr = attributes->get_attribute(attributes, OID_PKI_MESSAGE_TYPE);
-       if (attr.ptr)
+       if (pkcs7->get_attribute(pkcs7, OID_PKI_MESSAGE_TYPE, enumerator, &attr))
        {
                scep_msg_t m;
 
@@ -87,8 +86,7 @@ void extract_attributes(pkcs7_t *pkcs7, scep_attributes_t *attrs)
                }
                DBG2(DBG_APP, "messageType:  %s", msgType_names[attrs->msgType]);
        }
-       attr = attributes->get_attribute(attributes, OID_PKI_STATUS);
-       if (attr.ptr)
+       if (pkcs7->get_attribute(pkcs7, OID_PKI_STATUS, enumerator, &attr))
        {
                pkiStatus_t s;
 
@@ -101,8 +99,7 @@ void extract_attributes(pkcs7_t *pkcs7, scep_attributes_t *attrs)
                }
                DBG2(DBG_APP, "pkiStatus:    %s", pkiStatus_names[attrs->pkiStatus]);
        }
-       attr = attributes->get_attribute(attributes, OID_PKI_FAIL_INFO);
-       if (attr.ptr)
+       if (pkcs7->get_attribute(pkcs7, OID_PKI_FAIL_INFO, enumerator, &attr))
        {
                if (attr.len == 1 && *attr.ptr >= '0' && *attr.ptr <= '4')
                {
@@ -113,12 +110,13 @@ void extract_attributes(pkcs7_t *pkcs7, scep_attributes_t *attrs)
                        DBG1(DBG_APP, "failInfo:     %s", failInfo_reasons[attrs->failInfo]);
                }
        }
-       attrs->senderNonce = attributes->get_attribute(attributes,
-                                                                                       OID_PKI_SENDER_NONCE);
-       attrs->recipientNonce = attributes->get_attribute(attributes,
-                                                                                       OID_PKI_RECIPIENT_NONCE);
-       attrs->transID = attributes->get_attribute(attributes,
-                                                                                       OID_PKI_TRANS_ID);
+
+       pkcs7->get_attribute(pkcs7, OID_PKI_SENDER_NONCE, enumerator,
+                                                &attrs->senderNonce);
+       pkcs7->get_attribute(pkcs7, OID_PKI_RECIPIENT_NONCE, enumerator,
+                                                &attrs->recipientNonce);
+       pkcs7->get_attribute(pkcs7, OID_PKI_TRANS_ID, enumerator,
+                                                &attrs->transID);
 }
 
 /**
@@ -188,71 +186,81 @@ void scep_generate_transaction_id(public_key_t *key, chunk_t *transID,
 }
 
 /**
- * Adds a senderNonce attribute to the given pkcs9 attribute list
+ * Builds a pkcs7 enveloped and signed scep request
  */
-static bool add_senderNonce_attribute(pkcs9_t *pkcs9)
+chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
+                                       certificate_t *enc_cert, encryption_algorithm_t enc_alg,
+                                       size_t key_size, certificate_t *signer_cert,
+                                       hash_algorithm_t digest_alg, private_key_t *private_key)
 {
-       const size_t nonce_len = 16;
-       u_char nonce_buf[nonce_len];
-       chunk_t senderNonce = { nonce_buf, nonce_len };
+       chunk_t request;
+       container_t *container;
+       char nonce[16];
        rng_t *rng;
+       chunk_t senderNonce, msgType;
 
+       /* generate senderNonce */
        rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
-       if (!rng || !rng->get_bytes(rng, nonce_len, nonce_buf))
+       if (!rng || !rng->get_bytes(rng, sizeof(nonce), nonce))
        {
                DESTROY_IF(rng);
-               return FALSE;
+               return chunk_empty;
        }
        rng->destroy(rng);
 
-       pkcs9->add_attribute(pkcs9, OID_PKI_SENDER_NONCE,
-                                                asn1_wrap(ASN1_OCTET_STRING, "c", senderNonce));
-       return TRUE;
-}
-
-/**
- * Builds a pkcs7 enveloped and signed scep request
- */
-chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
-                                       certificate_t *enc_cert, encryption_algorithm_t enc_alg,
-                                       size_t key_size, certificate_t *signer_cert,
-                                       hash_algorithm_t digest_alg, private_key_t *private_key)
-{
-       chunk_t request, msgType = {
-               (u_char*)msgType_values[msg],
-               strlen(msgType_values[msg]),
-       };
-       pkcs7_t *pkcs7;
-       pkcs9_t *pkcs9;
-
-       pkcs7 = pkcs7_create_from_data(data);
-       if (!pkcs7->build_envelopedData(pkcs7, enc_cert, enc_alg, key_size))
+       /* encrypt data in enveloped-data PKCS#7 */
+       container = lib->creds->create(lib->creds,
+                                       CRED_CONTAINER, CONTAINER_PKCS7_ENVELOPED_DATA,
+                                       BUILD_BLOB, data,
+                                       BUILD_CERT, enc_cert,
+                                       BUILD_ENCRYPTION_ALG, enc_alg,
+                                       BUILD_KEY_SIZE, (int)key_size,
+                                       BUILD_END);
+       if (!container)
        {
-               pkcs7->destroy(pkcs7);
                return chunk_empty;
        }
-
-       pkcs9 = pkcs9_create();
-       pkcs9->add_attribute(pkcs9, OID_PKI_TRANS_ID,
-                                                asn1_wrap(ASN1_PRINTABLESTRING, "c", transID));
-       pkcs9->add_attribute(pkcs9, OID_PKI_MESSAGE_TYPE,
-                                                asn1_wrap(ASN1_PRINTABLESTRING, "c", msgType));
-       if (!add_senderNonce_attribute(pkcs9))
+       if (!container->get_encoding(container, &request))
        {
-               pkcs9->destroy(pkcs9);
-               pkcs7->destroy(pkcs7);
+               container->destroy(container);
                return chunk_empty;
        }
-
-       pkcs7->set_attributes(pkcs7, pkcs9);
-       pkcs7->set_certificate(pkcs7, signer_cert->get_ref(signer_cert));
-       if (!pkcs7->build_signedData(pkcs7, private_key, digest_alg))
+       container->destroy(container);
+
+       /* sign enveloped-data in a signed-data PKCS#7 */
+       senderNonce = asn1_wrap(ASN1_OCTET_STRING, "c", chunk_from_thing(nonce));
+       transID = asn1_wrap(ASN1_PRINTABLESTRING, "c", transID);
+       msgType = asn1_wrap(ASN1_PRINTABLESTRING, "c",
+                                               chunk_create((char*)msgType_values[msg],
+                                                                        strlen(msgType_values[msg])));
+
+       container = lib->creds->create(lib->creds,
+                                       CRED_CONTAINER, CONTAINER_PKCS7_SIGNED_DATA,
+                                       BUILD_BLOB, request,
+                                       BUILD_SIGNING_CERT, signer_cert,
+                                       BUILD_SIGNING_KEY, private_key,
+                                       BUILD_DIGEST_ALG, digest_alg,
+                                       BUILD_PKCS7_ATTRIBUTE, OID_PKI_SENDER_NONCE, senderNonce,
+                                       BUILD_PKCS7_ATTRIBUTE, OID_PKI_TRANS_ID, transID,
+                                       BUILD_PKCS7_ATTRIBUTE, OID_PKI_MESSAGE_TYPE, msgType,
+                                       BUILD_END);
+
+       free(request.ptr);
+       free(senderNonce.ptr);
+       free(transID.ptr);
+       free(msgType.ptr);
+
+       if (!container)
+       {
+               return chunk_empty;
+       }
+       if (!container->get_encoding(container, &request))
        {
-               pkcs7->destroy(pkcs7);
+               container->destroy(container);
                return chunk_empty;
        }
-       request = pkcs7->get_contentInfo(pkcs7);
-       pkcs7->destroy(pkcs7);
+       container->destroy(container);
+
        return request;
 }
 
@@ -400,23 +408,44 @@ bool scep_http_request(const char *url, chunk_t msg, scep_op_t op,
        return (status == SUCCESS);
 }
 
-err_t scep_parse_response(chunk_t response, chunk_t transID, pkcs7_t **data,
-                                                 scep_attributes_t *attrs, certificate_t *signer_cert)
+err_t scep_parse_response(chunk_t response, chunk_t transID,
+                                                 container_t **out, scep_attributes_t *attrs)
 {
-       pkcs7_t *pkcs7;
-
-       pkcs7 = pkcs7_create_from_chunk(response, 0);
-       if (!pkcs7 || !pkcs7->parse_signedData(pkcs7, signer_cert))
+       enumerator_t *enumerator;
+       bool verified = FALSE;
+       container_t *container;
+       auth_cfg_t *auth;
+
+       container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
+                                                                  BUILD_BLOB_ASN1_DER, response, BUILD_END);
+       if (!container)
        {
-               DESTROY_IF(pkcs7);
                return "error parsing the scep response";
        }
-       extract_attributes(pkcs7, attrs);
-       if (!chunk_equals(transID, attrs->transID))
+       if (container->get_type(container) != CONTAINER_PKCS7_SIGNED_DATA)
+       {
+               container->destroy(container);
+               return "scep response is not PKCS#7 signed-data";
+       }
+
+       enumerator = container->create_signature_enumerator(container);
+       while (enumerator->enumerate(enumerator, &auth))
+       {
+               verified = TRUE;
+               extract_attributes((pkcs7_t*)container, enumerator, attrs);
+               if (!chunk_equals(transID, attrs->transID))
+               {
+                       enumerator->destroy(enumerator);
+                       container->destroy(container);
+                       return "transaction ID of scep response does not match";
+               }
+       }
+       enumerator->destroy(enumerator);
+       if (!verified)
        {
-               pkcs7->destroy(pkcs7);
-               return "transaction ID of scep response does not match";
+               container->destroy(container);
+               return "unable to verify PKCS#7 container";
        }
-       *data = pkcs7;
+       *out = container;
        return NULL;
 }
index f0c180a..30551d2 100644 (file)
@@ -17,7 +17,7 @@
 #ifndef _SCEP_H
 #define _SCEP_H
 
-#include <crypto/pkcs7.h>
+#include <credentials/containers/pkcs7.h>
 #include <credentials/certificates/certificate.h>
 
 /* supported SCEP operation types */
@@ -81,7 +81,6 @@ chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
 bool scep_http_request(const char *url, chunk_t message, scep_op_t op,
                                           bool http_get_request, chunk_t *response);
 err_t scep_parse_response(chunk_t response, chunk_t transID,
-                                                 pkcs7_t **data, scep_attributes_t *attrs,
-                                                 certificate_t *signer_cert);
+                                                 container_t **out, scep_attributes_t *attrs);
 
 #endif /* _SCEP_H */
index e339345..0bae220 100644 (file)
@@ -40,6 +40,7 @@
 #include <credentials/certificates/certificate.h>
 #include <credentials/certificates/x509.h>
 #include <credentials/certificates/pkcs10.h>
+#include <credentials/sets/mem_cred.h>
 #include <plugins/plugin.h>
 
 #include "scep.h"
@@ -140,6 +141,8 @@ certificate_t *x509_ca_enc     = NULL;
 certificate_t *x509_ca_sig     = NULL;
 certificate_t *pkcs10_req      = NULL;
 
+mem_cred_t *creds              = NULL;
+
 /* logging */
 static bool log_to_stderr = TRUE;
 static bool log_to_syslog = TRUE;
@@ -255,6 +258,12 @@ static void exit_scepclient(err_t message, ...)
 {
        int status = 0;
 
+       if (creds)
+       {
+               lib->credmgr->remove_set(lib->credmgr, &creds->set);
+               creds->destroy(creds);
+       }
+
        DESTROY_IF(subject);
        DESTROY_IF(private_key);
        DESTROY_IF(public_key);
@@ -926,6 +935,7 @@ int main(int argc, char **argv)
        if (request_ca_certificate)
        {
                char ca_path[PATH_MAX];
+               container_t *container;
                pkcs7_t *pkcs7;
 
                if (!scep_http_request(scep_url, chunk_create(ca_name, strlen(ca_name)),
@@ -936,10 +946,13 @@ int main(int argc, char **argv)
 
                join_paths(ca_path, sizeof(ca_path), CA_CERT_PATH, file_out_ca_cert);
 
-               pkcs7 = pkcs7_create_from_chunk(scep_response, 0);
-               if (!pkcs7 || !pkcs7->parse_signedData(pkcs7, NULL))
+               pkcs7 = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
+                                                               BUILD_BLOB_ASN1_DER, scep_response, BUILD_END);
+
+               if (!pkcs7)
                {       /* no PKCS#7 encoded CA+RA certificates, assume simple CA cert */
-                       DESTROY_IF(pkcs7);
+
+                       DBG1(DBG_APP, "unable to parse PKCS#7, assuming plain CA cert");
                        if (!chunk_write(scep_response, ca_path, "ca cert",  0022, force))
                        {
                                exit_scepclient("could not write ca cert file '%s'", ca_path);
@@ -952,7 +965,7 @@ int main(int argc, char **argv)
                        int ra_certs = 0, ca_certs = 0;
                        int ra_index = 1, ca_index = 1;
 
-                       enumerator = pkcs7->create_certificate_enumerator(pkcs7);
+                       enumerator = pkcs7->create_cert_enumerator(pkcs7);
                        while (enumerator->enumerate(enumerator, &cert))
                        {
                                x509_t *x509 = (x509_t*)cert;
@@ -967,7 +980,7 @@ int main(int argc, char **argv)
                        }
                        enumerator->destroy(enumerator);
 
-                       enumerator = pkcs7->create_certificate_enumerator(pkcs7);
+                       enumerator = pkcs7->create_cert_enumerator(pkcs7);
                        while (enumerator->enumerate(enumerator, &cert))
                        {
                                x509_t *x509 = (x509_t*)cert;
@@ -1004,11 +1017,15 @@ int main(int argc, char **argv)
                                chunk_free(&encoding);
                        }
                        enumerator->destroy(enumerator);
-                       pkcs7->destroy(pkcs7);
+                       container = &pkcs7->container;
+                       container->destroy(container);
                }
                exit_scepclient(NULL); /* no further output required */
        }
 
+       creds = mem_cred_create();
+       lib->credmgr->add_set(lib->credmgr, &creds->set);
+
        /*
         * input of PKCS#1 file
         */
@@ -1031,6 +1048,7 @@ int main(int argc, char **argv)
        {
                exit_scepclient("no RSA private key available");
        }
+       creds->add_key(creds, private_key->get_ref(private_key));
        public_key = private_key->get_public_key(private_key);
 
        /* check for minimum key length */
@@ -1181,6 +1199,7 @@ int main(int argc, char **argv)
                        exit_scepclient("generating certificate failed");
                }
        }
+       creds->add_cert(creds, TRUE, x509_signer->get_ref(x509_signer));
 
        /*
         * output of self-signed X.509 certificate file
@@ -1281,7 +1300,9 @@ int main(int argc, char **argv)
                enumerator_t  *enumerator;
                char path[PATH_MAX];
                time_t poll_start = 0;
-               pkcs7_t *data = NULL;
+               pkcs7_t *p7;
+               container_t *container = NULL;
+               chunk_t chunk;
                scep_attributes_t attrs = empty_scep_attributes;
 
                join_paths(path, sizeof(path), CA_CERT_PATH, file_in_cacert_sig);
@@ -1293,13 +1314,14 @@ int main(int argc, char **argv)
                        exit_scepclient("could not load signature cacert file '%s'", path);
                }
 
+               creds->add_cert(creds, TRUE, x509_ca_sig->get_ref(x509_ca_sig));
+
                if (!scep_http_request(scep_url, pkcs7, SCEP_PKI_OPERATION,
                                http_get_request, &scep_response))
                {
                        exit_scepclient("did not receive a valid scep response");
                }
-               ugh = scep_parse_response(scep_response, transID, &data, &attrs,
-                                                                 x509_ca_sig);
+               ugh = scep_parse_response(scep_response, transID, &container, &attrs);
                if (ugh != NULL)
                {
                        exit_scepclient(ugh);
@@ -1328,7 +1350,7 @@ int main(int argc, char **argv)
                        DBG2(DBG_APP, "going to sleep for %d seconds", poll_interval);
                        sleep(poll_interval);
                        free(scep_response.ptr);
-                       data->destroy(data);
+                       container->destroy(container);
 
                        DBG2(DBG_APP, "fingerprint:    %.*s",
                                 (int)fingerprint.len, fingerprint.ptr);
@@ -1349,8 +1371,7 @@ int main(int argc, char **argv)
                        {
                                exit_scepclient("did not receive a valid scep response");
                        }
-                       ugh = scep_parse_response(scep_response, transID, &data, &attrs,
-                                                                         x509_ca_sig);
+                       ugh = scep_parse_response(scep_response, transID, &container, &attrs);
                        if (ugh != NULL)
                        {
                                exit_scepclient(ugh);
@@ -1359,25 +1380,53 @@ int main(int argc, char **argv)
 
                if (attrs.pkiStatus != SCEP_SUCCESS)
                {
-                       data->destroy(data);
+                       container->destroy(container);
                        exit_scepclient("reply status is not 'SUCCESS'");
                }
 
-               if (!data->parse_envelopedData(data, serialNumber, private_key))
+               if (!container->get_data(container, &chunk))
+               {
+                       container->destroy(container);
+                       exit_scepclient("extracting signed-data failed");
+               }
+               container->destroy(container);
+
+               /* decrypt enveloped-data container */
+               container = lib->creds->create(lib->creds,
+                                                                          CRED_CONTAINER, CONTAINER_PKCS7,
+                                                                          BUILD_BLOB_ASN1_DER, chunk,
+                                                                          BUILD_END);
+               free(chunk.ptr);
+               if (!container)
                {
-                       data->destroy(data);
                        exit_scepclient("could not decrypt envelopedData");
                }
-               if (!data->parse_signedData(data, NULL))
+
+               if (!container->get_data(container, &chunk))
+               {
+                       container->destroy(container);
+                       exit_scepclient("extracting signed-data failed");
+               }
+               container->destroy(container);
+
+               /* parse signed-data container */
+               container = lib->creds->create(lib->creds,
+                                                                          CRED_CONTAINER, CONTAINER_PKCS7,
+                                                                          BUILD_BLOB_ASN1_DER, chunk,
+                                                                          BUILD_END);
+               free(chunk.ptr);
+               if (!container)
                {
-                       data->destroy(data);
-                       exit_scepclient("error parsing the scep response");
+                       exit_scepclient("could not parse singed-data");
                }
+               /* no need to verify the signed-data container, the signature does NOT
+                * cover the contained certificates */
 
                /* store the end entity certificate */
                join_paths(path, sizeof(path), HOST_CERT_PATH, file_out_cert);
 
-               enumerator = data->create_certificate_enumerator(data);
+               p7 = (pkcs7_t*)container;
+               enumerator = p7->create_cert_enumerator(p7);
                while (enumerator->enumerate(enumerator, &cert))
                {
                        x509_t *x509 = (x509_t*)cert;
@@ -1398,7 +1447,7 @@ int main(int argc, char **argv)
                        }
                }
                enumerator->destroy(enumerator);
-               data->destroy(data);
+               container->destroy(container);
                filetype_out &= ~CERT;   /* delete CERT flag */
        }