summaryrefslogtreecommitdiff
path: root/src/pluto/ocsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pluto/ocsp.c')
-rw-r--r--src/pluto/ocsp.c2396
1 files changed, 1188 insertions, 1208 deletions
diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c
index 74b86bf19..80164fa1d 100644
--- a/src/pluto/ocsp.c
+++ b/src/pluto/ocsp.c
@@ -11,8 +11,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
- *
- * RCSID $Id: ocsp.c 4827 2009-01-09 01:36:13Z andreas $
*/
#include <unistd.h>
@@ -24,7 +22,13 @@
#include <fcntl.h>
#include <freeswan.h>
-#include <ipsec_policy.h>
+
+#include <library.h>
+#include <asn1/asn1.h>
+#include <asn1/asn1_parser.h>
+#include <asn1/oid.h>
+#include <crypto/rngs/rng.h>
+#include <crypto/hashers/hasher.h>
#include "constants.h"
#include "defs.h"
@@ -32,120 +36,116 @@
#include "x509.h"
#include "crl.h"
#include "ca.h"
-#include "rnd.h"
-#include "asn1.h"
#include "certs.h"
#include "smartcard.h"
-#include <asn1/oid.h>
#include "whack.h"
-#include "pkcs1.h"
#include "keys.h"
#include "fetch.h"
#include "ocsp.h"
-#define NONCE_LENGTH 16
+#define NONCE_LENGTH 16
static const char *const cert_status_names[] = {
- "good",
- "revoked",
- "unknown",
- "undefined"
+ "good",
+ "revoked",
+ "unknown",
+ "undefined"
};
static const char *const response_status_names[] = {
- "successful",
- "malformed request",
- "internal error",
- "try later",
- "status #4",
- "signature required",
- "unauthorized"
+ "successful",
+ "malformed request",
+ "internal error",
+ "try later",
+ "status #4",
+ "signature required",
+ "unauthorized"
};
/* response container */
typedef struct response response_t;
struct response {
- chunk_t tbs;
- chunk_t responder_id_name;
- chunk_t responder_id_key;
- time_t produced_at;
- chunk_t responses;
- chunk_t nonce;
- int algorithm;
- chunk_t signature;
+ chunk_t tbs;
+ chunk_t responder_id_name;
+ chunk_t responder_id_key;
+ time_t produced_at;
+ chunk_t responses;
+ chunk_t nonce;
+ int algorithm;
+ chunk_t signature;
};
const response_t empty_response = {
- { NULL, 0 } , /* tbs */
- { NULL, 0 } , /* responder_id_name */
- { NULL, 0 } , /* responder_id_key */
- UNDEFINED_TIME, /* produced_at */
- { NULL, 0 } , /* single_response */
- { NULL, 0 } , /* nonce */
- OID_UNKNOWN , /* signature_algorithm */
- { NULL, 0 } /* signature */
+ { NULL, 0 } , /* tbs */
+ { NULL, 0 } , /* responder_id_name */
+ { NULL, 0 } , /* responder_id_key */
+ UNDEFINED_TIME, /* produced_at */
+ { NULL, 0 } , /* single_response */
+ { NULL, 0 } , /* nonce */
+ OID_UNKNOWN , /* signature_algorithm */
+ { NULL, 0 } /* signature */
};
/* single response container */
typedef struct single_response single_response_t;
struct single_response {
- single_response_t *next;
- int hash_algorithm;
- chunk_t issuer_name_hash;
- chunk_t issuer_key_hash;
- chunk_t serialNumber;
- cert_status_t status;
- time_t revocationTime;
- crl_reason_t revocationReason;
- time_t thisUpdate;
- time_t nextUpdate;
+ single_response_t *next;
+ int hash_algorithm;
+ chunk_t issuer_name_hash;
+ chunk_t issuer_key_hash;
+ chunk_t serialNumber;
+ cert_status_t status;
+ time_t revocationTime;
+ crl_reason_t revocationReason;
+ time_t thisUpdate;
+ time_t nextUpdate;
};
const single_response_t empty_single_response = {
- NULL , /* *next */
- OID_UNKNOWN , /* hash_algorithm */
- { NULL, 0 } , /* issuer_name_hash */
- { NULL, 0 } , /* issuer_key_hash */
- { NULL, 0 } , /* serial_number */
- CERT_UNDEFINED , /* status */
- UNDEFINED_TIME , /* revocationTime */
- REASON_UNSPECIFIED, /* revocationReason */
- UNDEFINED_TIME , /* this_update */
- UNDEFINED_TIME /* next_update */
+ NULL , /* *next */
+ OID_UNKNOWN , /* hash_algorithm */
+ { NULL, 0 } , /* issuer_name_hash */
+ { NULL, 0 } , /* issuer_key_hash */
+ { NULL, 0 } , /* serial_number */
+ CERT_UNDEFINED , /* status */
+ UNDEFINED_TIME , /* revocationTime */
+ REASON_UNSPECIFIED, /* revocationReason */
+ UNDEFINED_TIME , /* this_update */
+ UNDEFINED_TIME /* next_update */
};
/* list of single requests */
typedef struct request_list request_list_t;
struct request_list {
- chunk_t request;
- request_list_t *next;
+ chunk_t request;
+ request_list_t *next;
};
/* some OCSP specific prefabricated ASN.1 constants */
static u_char ASN1_nonce_oid_str[] = {
- 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
};
-static const chunk_t ASN1_nonce_oid = strchunk(ASN1_nonce_oid_str);
+static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str);
static u_char ASN1_response_oid_str[] = {
- 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
};
-static const chunk_t ASN1_response_oid = strchunk(ASN1_response_oid_str);
+static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str);
static u_char ASN1_response_content_str[] = {
- 0x04, 0x0D,
- 0x30, 0x0B,
- 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+ 0x04, 0x0D,
+ 0x30, 0x0B,
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
};
-static const chunk_t ASN1_response_content = strchunk(ASN1_response_content_str);
+static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str);
/* default OCSP uri */
static chunk_t ocsp_default_uri;
@@ -158,57 +158,60 @@ static x509cert_t *ocsp_requestor_cert = NULL;
static smartcard_t *ocsp_requestor_sc = NULL;
-static const struct RSA_private_key *ocsp_requestor_pri = NULL;
-
-/* asn.1 definitions for parsing */
+static private_key_t *ocsp_requestor_key = NULL;
+/**
+ * ASN.1 definition of ocspResponse
+ */
static const asn1Object_t ocspResponseObjects[] = {
- { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
- { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
- { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
- { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
- { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
- { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
- { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */
+ { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
+ { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
+ { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
+ { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
+ { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
-
#define OCSP_RESPONSE_STATUS 1
-#define OCSP_RESPONSE_TYPE 4
-#define OCSP_RESPONSE 5
-#define OCSP_RESPONSE_ROOF 7
+#define OCSP_RESPONSE_TYPE 4
+#define OCSP_RESPONSE 5
+/**
+ * ASN.1 definition of basicResponse
+ */
static const asn1Object_t basicResponseObjects[] = {
- { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
- { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
- { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
- ASN1_DEF }, /* 2 */
- { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
- { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
- { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
- { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
- { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
- { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
- { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
- { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
- { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
- { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
- { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
- { 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
- ASN1_DEF }, /* 16 */
- { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
- { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
- { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
- { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
- { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
- { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
- { 3, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 24 */
- { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
- { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */
+ { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
+ ASN1_DEF }, /* 2 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
+ { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
+ { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
+ { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
+ { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
+ { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
+ { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
+ ASN1_DEF }, /* 16 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
+ { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
+ { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
+ { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
+ { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
+ { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
-
#define BASIC_RESPONSE_TBS_DATA 1
#define BASIC_RESPONSE_VERSION 3
#define BASIC_RESPONSE_ID_BY_NAME 5
@@ -221,1349 +224,1326 @@ static const asn1Object_t basicResponseObjects[] = {
#define BASIC_RESPONSE_ALGORITHM 20
#define BASIC_RESPONSE_SIGNATURE 21
#define BASIC_RESPONSE_CERTIFICATE 24
-#define BASIC_RESPONSE_ROOF 27
+/**
+ * ASN.1 definition of responses
+ */
static const asn1Object_t responsesObjects[] = {
- { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
- { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
- { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */
+ { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
+#define RESPONSES_SINGLE_RESPONSE 1
-#define RESPONSES_SINGLE_RESPONSE 1
-#define RESPONSES_ROOF 3
-
+/**
+ * ASN.1 definition of singleResponse
+ */
static const asn1Object_t singleResponseObjects[] = {
- { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
- { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
- { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
- { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
- { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
- { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
- { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
- { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
- { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
- { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
- { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
- { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
- { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
- { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
- { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
- { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
- { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
- { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
- { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
- { 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
- ASN1_DEF }, /* 24 */
- { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
- { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
- { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */
+ { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
+ { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
+ { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
+ { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
+ { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
+ { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
+ { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
+ { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
+ { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
+ { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
+ { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
+ { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
+ { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
+ { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
+ { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
+ { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
+ { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
+ { 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
+ ASN1_DEF }, /* 24 */
+ { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
-
-#define SINGLE_RESPONSE_ALGORITHM 2
-#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
-#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
-#define SINGLE_RESPONSE_SERIAL_NUMBER 5
-#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
-#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
+#define SINGLE_RESPONSE_ALGORITHM 2
+#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
+#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
+#define SINGLE_RESPONSE_SERIAL_NUMBER 5
+#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
+#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9
#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11
-#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
-#define SINGLE_RESPONSE_THIS_UPDATE 16
-#define SINGLE_RESPONSE_NEXT_UPDATE 18
-#define SINGLE_RESPONSE_EXT_ID 23
-#define SINGLE_RESPONSE_CRITICAL 24
-#define SINGLE_RESPONSE_EXT_VALUE 25
-#define SINGLE_RESPONSE_ROOF 28
-
-/* build an ocsp location from certificate information
+#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
+#define SINGLE_RESPONSE_THIS_UPDATE 16
+#define SINGLE_RESPONSE_NEXT_UPDATE 18
+#define SINGLE_RESPONSE_EXT_ID 23
+#define SINGLE_RESPONSE_CRITICAL 24
+#define SINGLE_RESPONSE_EXT_VALUE 25
+
+/*
+ * Build an ocsp location from certificate information
* without unsharing its contents
*/
-static bool
-build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
+static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
{
- static u_char digest[SHA1_DIGEST_SIZE]; /* temporary storage */
+ hasher_t *hasher;
+ static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */
+
+ location->uri = cert->accessLocation;
- location->uri = cert->accessLocation;
+ if (location->uri.ptr == NULL)
+ {
+ ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID);
+ if (ca != NULL && ca->ocspuri != NULL)
+ {
+ location->uri = chunk_create(ca->ocspuri, strlen(ca->ocspuri));
+ }
+ else
+ { /* abort if no ocsp location uri is defined */
+ return FALSE;
+ }
+ }
+
+ /* compute authNameID from as SHA-1 hash of issuer DN */
+ location->authNameID = chunk_create(digest, HASH_SIZE_SHA1);
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (hasher == NULL)
+ {
+ return FALSE;
+ }
+ hasher->get_hash(hasher, cert->issuer, digest);
+ hasher->destroy(hasher);
- if (location->uri.ptr == NULL)
- {
- ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
- , cert->authKeyID);
- if (ca != NULL && ca->ocspuri != NULL)
- setchunk(location->uri, ca->ocspuri, strlen(ca->ocspuri))
- else
- /* abort if no ocsp location uri is defined */
- return FALSE;
- }
-
- setchunk(location->authNameID, digest, SHA1_DIGEST_SIZE);
- compute_digest(cert->issuer, OID_SHA1, &location->authNameID);
-
- location->next = NULL;
- location->issuer = cert->issuer;
- location->authKeyID = cert->authKeyID;
- location->authKeySerialNumber = cert->authKeySerialNumber;
-
- if (cert->authKeyID.ptr == NULL)
- {
- x509cert_t *authcert = get_authcert(cert->issuer
- , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA);
-
- if (authcert != NULL)
+ location->next = NULL;
+ location->issuer = cert->issuer;
+ location->authKeyID = cert->authKeyID;
+ location->authKeySerialNumber = cert->authKeySerialNumber;
+
+ if (cert->authKeyID.ptr == NULL)
{
- location->authKeyID = authcert->subjectKeyID;
- location->authKeySerialNumber = authcert->serialNumber;
+ x509cert_t *authcert = get_authcert(cert->issuer
+ , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA);
+
+ if (authcert != NULL)
+ {
+ location->authKeyID = authcert->subjectKeyID;
+ location->authKeySerialNumber = authcert->serialNumber;
+ }
}
- }
- location->nonce = empty_chunk;
- location->certinfo = NULL;
+ location->nonce = chunk_empty;
+ location->certinfo = NULL;
- return TRUE;
+ return TRUE;
}
-/*
- * compare two ocsp locations for equality
+/**
+ * Compare two ocsp locations for equality
*/
-static bool
-same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b)
+static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b)
{
- return ((a->authKeyID.ptr != NULL)
- ? same_keyid(a->authKeyID, b->authKeyID)
- : (same_dn(a->issuer, b->issuer)
- && same_serial(a->authKeySerialNumber, b->authKeySerialNumber)))
- && same_chunk(a->uri, b->uri);
+ return ((a->authKeyID.ptr != NULL)
+ ? same_keyid(a->authKeyID, b->authKeyID)
+ : (same_dn(a->issuer, b->issuer)
+ && same_serial(a->authKeySerialNumber, b->authKeySerialNumber)))
+ && chunk_equals(a->uri, b->uri);
}
-/*
- * find an existing ocsp location in a chained list
+/**
+ * Find an existing ocsp location in a chained list
*/
-ocsp_location_t*
-get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain)
+ocsp_location_t* get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain)
{
- while (chain != NULL)
- {
- if (same_ocsp_location(loc, chain))
- return chain;
- chain = chain->next;
- }
- return NULL;
+ while (chain != NULL)
+ {
+ if (same_ocsp_location(loc, chain))
+ return chain;
+ chain = chain->next;
+ }
+ return NULL;
}
-
-/* retrieves the status of a cert from the ocsp cache
+
+/**
+ * Retrieves the status of a cert from the ocsp cache
* returns CERT_UNDEFINED if no status is found
*/
-static cert_status_t
-get_ocsp_status(const ocsp_location_t *loc, chunk_t serialNumber
- ,time_t *nextUpdate, time_t *revocationTime, crl_reason_t *revocationReason)
+static cert_status_t get_ocsp_status(const ocsp_location_t *loc,
+ chunk_t serialNumber,
+ time_t *nextUpdate, time_t *revocationTime,
+ crl_reason_t *revocationReason)
{
- ocsp_certinfo_t *certinfo, **certinfop;
- int cmp = -1;
+ ocsp_certinfo_t *certinfo, **certinfop;
+ int cmp = -1;
- /* find location */
- ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache);
+ /* find location */
+ ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache);
- if (location == NULL)
- return CERT_UNDEFINED;
-
- /* traverse list of certinfos in increasing order */
- certinfop = &location->certinfo;
- certinfo = *certinfop;
+ if (location == NULL)
+ return CERT_UNDEFINED;
- while (certinfo != NULL)
- {
- cmp = cmp_chunk(serialNumber, certinfo->serialNumber);
- if (cmp <= 0)
- break;
- certinfop = &certinfo->next;
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
certinfo = *certinfop;
- }
- if (cmp == 0)
- {
- *nextUpdate = certinfo->nextUpdate;
- *revocationTime = certinfo->revocationTime;
- *revocationReason = certinfo->revocationReason;
- return certinfo->status;
- }
+ while (certinfo != NULL)
+ {
+ cmp = chunk_compare(serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
+ if (cmp == 0)
+ {
+ *nextUpdate = certinfo->nextUpdate;
+ *revocationTime = certinfo->revocationTime;
+ *revocationReason = certinfo->revocationReason;
+ return certinfo->status;
+ }
- return CERT_UNDEFINED;
+ return CERT_UNDEFINED;
}
-/*
- * verify the ocsp status of a certificate
+/**
+ * Verify the ocsp status of a certificate
*/
-cert_status_t
-verify_by_ocsp(const x509cert_t *cert, time_t *until
-, time_t *revocationDate, crl_reason_t *revocationReason)
+cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until,
+ time_t *revocationDate,
+ crl_reason_t *revocationReason)
{
- cert_status_t status;
- ocsp_location_t location;
- time_t nextUpdate = 0;
-
- *revocationDate = UNDEFINED_TIME;
- *revocationReason = REASON_UNSPECIFIED;
-
- /* is an ocsp location defined? */
- if (!build_ocsp_location(cert, &location))
- return CERT_UNDEFINED;
+ cert_status_t status;
+ ocsp_location_t location;
+ time_t nextUpdate = 0;
+
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
+
+ /* is an ocsp location defined? */
+ if (!build_ocsp_location(cert, &location))
+ return CERT_UNDEFINED;
+
+ lock_ocsp_cache("verify_by_ocsp");
+ status = get_ocsp_status(&location, cert->serialNumber, &nextUpdate
+ , revocationDate, revocationReason);
+ unlock_ocsp_cache("verify_by_ocsp");
+
+ if (status == CERT_UNDEFINED || nextUpdate < time(NULL))
+ {
+ plog("ocsp status is stale or not in cache");
+ add_ocsp_fetch_request(&location, cert->serialNumber);
- lock_ocsp_cache("verify_by_ocsp");
- status = get_ocsp_status(&location, cert->serialNumber, &nextUpdate
- , revocationDate, revocationReason);
- unlock_ocsp_cache("verify_by_ocsp");
-
- if (status == CERT_UNDEFINED || nextUpdate < time(NULL))
- {
- plog("ocsp status is stale or not in cache");
- add_ocsp_fetch_request(&location, cert->serialNumber);
-
- /* inititate fetching of ocsp status */
- wake_fetch_thread("verify_by_ocsp");
- }
- *until = nextUpdate;
- return status;
+ /* inititate fetching of ocsp status */
+ wake_fetch_thread("verify_by_ocsp");
+ }
+ *until = nextUpdate;
+ return status;
}
-/*
- * check if an ocsp status is about to expire
+/**
+ * Check if an ocsp status is about to expire
*/
-void
-check_ocsp(void)
+void check_ocsp(void)
{
- ocsp_location_t *location;
-
- lock_ocsp_cache("check_ocsp");
- location = ocsp_cache;
-
- while (location != NULL)
- {
- char buf[BUF_LEN];
- bool first = TRUE;
- ocsp_certinfo_t *certinfo = location->certinfo;
+ ocsp_location_t *location;
- while (certinfo != NULL)
+ lock_ocsp_cache("check_ocsp");
+ location = ocsp_cache;
+
+ while (location != NULL)
{
- if (!certinfo->once)
- {
- time_t time_left = certinfo->nextUpdate - time(NULL);
+ char buf[BUF_LEN];
+ bool first = TRUE;
+ ocsp_certinfo_t *certinfo = location->certinfo;
- DBG(DBG_CONTROL,
- if (first)
- {
- dntoa(buf, BUF_LEN, location->issuer);
- DBG_log("issuer: '%s'", buf);
- if (location->authKeyID.ptr != NULL)
+ while (certinfo != NULL)
+ {
+ if (!certinfo->once)
{
- datatot(location->authKeyID.ptr, location->authKeyID.len
- , ':', buf, BUF_LEN);
- DBG_log("authkey: %s", buf);
+ time_t time_left = certinfo->nextUpdate - time(NULL);
+
+ DBG(DBG_CONTROL,
+ if (first)
+ {
+ dntoa(buf, BUF_LEN, location->issuer);
+ DBG_log("issuer: '%s'", buf);
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len
+ , ':', buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ first = FALSE;
+ }
+ datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len
+ , ':', buf, BUF_LEN);
+ DBG_log("serial: %s, %ld seconds left", buf, time_left)
+ )
+
+ if (time_left < 2*crl_check_interval)
+ add_ocsp_fetch_request(location, certinfo->serialNumber);
}
- first = FALSE;
- }
- datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len
- , ':', buf, BUF_LEN);
- DBG_log("serial: %s, %ld seconds left", buf, time_left)
- )
-
- if (time_left < 2*crl_check_interval)
- add_ocsp_fetch_request(location, certinfo->serialNumber);
- }
- certinfo = certinfo->next;
+ certinfo = certinfo->next;
+ }
+ location = location->next;
}
- location = location->next;
- }
- unlock_ocsp_cache("check_ocsp");
+ unlock_ocsp_cache("check_ocsp");
}
-/*
+/**
* frees the allocated memory of a certinfo struct
*/
-static void
-free_certinfo(ocsp_certinfo_t *certinfo)
+static void free_certinfo(ocsp_certinfo_t *certinfo)
{
- freeanychunk(certinfo->serialNumber);
- pfree(certinfo);
+ free(certinfo->serialNumber.ptr);
+ free(certinfo);
}
-/*
+/**
* frees all certinfos in a chained list
*/
-static void
-free_certinfos(ocsp_certinfo_t *chain)
+static void free_certinfos(ocsp_certinfo_t *chain)
{
- ocsp_certinfo_t *certinfo;
+ ocsp_certinfo_t *certinfo;
- while (chain != NULL)
- {
- certinfo = chain;
- chain = chain->next;
- free_certinfo(certinfo);
- }
+ while (chain != NULL)
+ {
+ certinfo = chain;
+ chain = chain->next;
+ free_certinfo(certinfo);
+ }
}
-/*
- * frees the memory allocated to an ocsp location including all certinfos
+/**
+ * Frees the memory allocated to an ocsp location including all certinfos
*/
-static void
-free_ocsp_location(ocsp_location_t* location)
+static void free_ocsp_location(ocsp_location_t* location)
{
- freeanychunk(location->issuer);
- freeanychunk(location->authNameID);
- freeanychunk(location->authKeyID);
- freeanychunk(location->authKeySerialNumber);
- freeanychunk(location->uri);
- free_certinfos(location->certinfo);
- pfree(location);
+ free(location->issuer.ptr);
+ free(location->authNameID.ptr);
+ free(location->authKeyID.ptr);
+ free(location->authKeySerialNumber.ptr);
+ free(location->uri.ptr);
+ free_certinfos(location->certinfo);
+ free(location);
}
/*
- * free a chained list of ocsp locations
+ * Free a chained list of ocsp locations
*/
-void
-free_ocsp_locations(ocsp_location_t **chain)
+void free_ocsp_locations(ocsp_location_t **chain)
{
- while (*chain != NULL)
- {
- ocsp_location_t *location = *chain;
- *chain = location->next;
- free_ocsp_location(location);
- }
+ while (*chain != NULL)
+ {
+ ocsp_location_t *location = *chain;
+ *chain = location->next;
+ free_ocsp_location(location);
+ }
}
-/*
- * free the ocsp cache
+/**
+ * Free the ocsp cache
*/
-void
-free_ocsp_cache(void)
+void free_ocsp_cache(void)
{
- lock_ocsp_cache("free_ocsp_cache");
- free_ocsp_locations(&ocsp_cache);
- unlock_ocsp_cache("free_ocsp_cache");
+ lock_ocsp_cache("free_ocsp_cache");
+ free_ocsp_locations(&ocsp_cache);
+ unlock_ocsp_cache("free_ocsp_cache");
}
-/*
- * frees the ocsp cache and global variables
+/**
+ * Frees the ocsp cache and global variables
*/
-void
-free_ocsp(void)
+void free_ocsp(void)
{
- pfreeany(ocsp_default_uri.ptr);
- free_ocsp_cache();
+ free(ocsp_default_uri.ptr);
+ free_ocsp_cache();
}
-/*
- * list a chained list of ocsp_locations
+/**
+ * List a chained list of ocsp_locations
*/
-void
-list_ocsp_locations(ocsp_location_t *location, bool requests, bool utc
-, bool strict)
+void list_ocsp_locations(ocsp_location_t *location, bool requests,
+ bool utc, bool strict)
{
- bool first = TRUE;
-
- while (location != NULL)
- {
- ocsp_certinfo_t *certinfo = location->certinfo;
+ bool first = TRUE;
- if (certinfo != NULL)
+ while (location != NULL)
{
- u_char buf[BUF_LEN];
-
- if (first)
- {
- whack_log(RC_COMMENT, " ");
- whack_log(RC_COMMENT, "List of OCSP %s:", requests?
- "fetch requests":"responses");
- first = FALSE;
- }
- whack_log(RC_COMMENT, " ");
- if (location->issuer.ptr != NULL)
- {
- dntoa(buf, BUF_LEN, location->issuer);
- whack_log(RC_COMMENT, " issuer: '%s'", buf);
- }
- whack_log(RC_COMMENT, " uri: '%.*s'", (int)location->uri.len
- , location->uri.ptr);
- if (location->authNameID.ptr != NULL)
- {
- datatot(location->authNameID.ptr, location->authNameID.len, ':'
- , buf, BUF_LEN);
- whack_log(RC_COMMENT, " authname: %s", buf);
- }
- if (location->authKeyID.ptr != NULL)
- {
- datatot(location->authKeyID.ptr, location->authKeyID.len, ':'
- , buf, BUF_LEN);
- whack_log(RC_COMMENT, " authkey: %s", buf);
- }
- if (location->authKeySerialNumber.ptr != NULL)
- {
- datatot(location->authKeySerialNumber.ptr
- , location->authKeySerialNumber.len, ':', buf, BUF_LEN);
- whack_log(RC_COMMENT, " aserial: %s", buf);
- }
- while (certinfo != NULL)
- {
- char thisUpdate[TIMETOA_BUF];
-
- strcpy(thisUpdate, timetoa(&certinfo->thisUpdate, utc));
-
- if (requests)
- {
- whack_log(RC_COMMENT, "%s, trials: %d", thisUpdate
- , certinfo->trials);
- }
- else if (certinfo->once)
- {
- whack_log(RC_COMMENT, "%s, onetime use%s", thisUpdate
- , (certinfo->nextUpdate < time(NULL))? " (expired)": "");
- }
- else
+ ocsp_certinfo_t *certinfo = location->certinfo;
+
+ if (certinfo != NULL)
{
- whack_log(RC_COMMENT, "%s, until %s %s", thisUpdate
- , timetoa(&certinfo->nextUpdate, utc)
- , check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict));
+ u_char buf[BUF_LEN];
+
+ if (first)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of OCSP %s:", requests?
+ "fetch requests":"responses");
+ first = FALSE;
+ }
+ whack_log(RC_COMMENT, " ");
+ if (location->issuer.ptr != NULL)
+ {
+ dntoa(buf, BUF_LEN, location->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ }
+ whack_log(RC_COMMENT, " uri: '%.*s'", (int)location->uri.len
+ , location->uri.ptr);
+ if (location->authNameID.ptr != NULL)
+ {
+ datatot(location->authNameID.ptr, location->authNameID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authname: %s", buf);
+ }
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (location->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(location->authKeySerialNumber.ptr
+ , location->authKeySerialNumber.len, ':', buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ while (certinfo != NULL)
+ {
+ char thisUpdate[BUF_LEN];
+
+ snprintf(thisUpdate, BUF_LEN, "%T", &certinfo->thisUpdate, utc);
+
+ if (requests)
+ {
+ whack_log(RC_COMMENT, "%s, trials: %d", thisUpdate
+ , certinfo->trials);
+ }
+ else if (certinfo->once)
+ {
+ whack_log(RC_COMMENT, "%s, onetime use%s", thisUpdate
+ , (certinfo->nextUpdate < time(NULL))? " (expired)": "");
+ }
+ else
+ {
+ whack_log(RC_COMMENT, "%s, until %T %s", thisUpdate
+ , &certinfo->nextUpdate, utc
+ , check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict));
+ }
+ datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " serial: %s, %s", buf
+ , cert_status_names[certinfo->status]);
+ certinfo = certinfo->next;
+ }
}
- datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len, ':'
- , buf, BUF_LEN);
- whack_log(RC_COMMENT, " serial: %s, %s", buf
- , cert_status_names[certinfo->status]);
- certinfo = certinfo->next;
- }
+ location = location->next;
}
- location = location->next;
- }
}
-/*
- * list the ocsp cache
+/**
+ * List the ocsp cache
*/
-void
-list_ocsp_cache(bool utc, bool strict)
+void list_ocsp_cache(bool utc, bool strict)
{
- lock_ocsp_cache("list_ocsp_cache");
- list_ocsp_locations(ocsp_cache, FALSE, utc, strict);
- unlock_ocsp_cache("list_ocsp_cache");
+ lock_ocsp_cache("list_ocsp_cache");
+ list_ocsp_locations(ocsp_cache, FALSE, utc, strict);
+ unlock_ocsp_cache("list_ocsp_cache");
}
-static bool
-get_ocsp_requestor_cert(ocsp_location_t *location)
+static bool get_ocsp_requestor_cert(ocsp_location_t *location)
{
- x509cert_t *cert = NULL;
+ x509cert_t *cert = NULL;
- /* initialize temporary static storage */
- ocsp_requestor_cert = NULL;
- ocsp_requestor_sc = NULL;
- ocsp_requestor_pri = NULL;
+ /* initialize temporary static storage */
+ ocsp_requestor_cert = NULL;
+ ocsp_requestor_sc = NULL;
+ ocsp_requestor_key = NULL;
- for (;;)
- {
- char buf[BUF_LEN];
-
- /* looking for a certificate from the same issuer */
- cert = get_x509cert(location->issuer, location->authKeySerialNumber
- ,location->authKeyID, cert);
- if (cert == NULL)
- break;
-
- DBG(DBG_CONTROL,
- dntoa(buf, BUF_LEN, cert->subject);
- DBG_log("candidate: '%s'", buf);
- )
-
- if (cert->smartcard)
+ for (;;)
{
- /* look for a matching private key on a smartcard */
- smartcard_t *sc = scx_get(cert);
+ char buf[BUF_LEN];
+
+ /* looking for a certificate from the same issuer */
+ cert = get_x509cert(location->issuer, location->authKeySerialNumber
+ ,location->authKeyID, cert);
+ if (cert == NULL)
+ break;
- if (sc != NULL)
- {
DBG(DBG_CONTROL,
- DBG_log("matching smartcard found")
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("candidate: '%s'", buf);
)
- if (sc->valid)
+
+ if (cert->smartcard)
{
- ocsp_requestor_cert = cert;
- ocsp_requestor_sc = sc;
- return TRUE;
+ /* look for a matching private key on a smartcard */
+ smartcard_t *sc = scx_get(cert);
+
+ if (sc != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("matching smartcard found")
+ )
+ if (sc->valid)
+ {
+ ocsp_requestor_cert = cert;
+ ocsp_requestor_sc = sc;
+ return TRUE;
+ }
+ plog("unable to sign ocsp request without PIN");
+ }
}
- plog("unable to sign ocsp request without PIN");
- }
- }
- else
- {
- /* look for a matching private key in the chained list */
- const struct RSA_private_key *pri = get_x509_private_key(cert);
+ else
+ {
+ /* look for a matching private key in the chained list */
+ private_key_t *private = get_x509_private_key(cert);
- if (pri != NULL)
- {
- DBG(DBG_CONTROL,
- DBG_log("matching private key found")
- )
- ocsp_requestor_cert = cert;
- ocsp_requestor_pri = pri;
- return TRUE;
- }
+ if (private != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("matching private key found")
+ )
+ ocsp_requestor_cert = cert;
+ ocsp_requestor_key = private;
+ return TRUE;
+ }
+ }
}
- }
- return FALSE;
+ return FALSE;
}
-static chunk_t
-generate_signature(chunk_t digest, smartcard_t *sc
- , const RSA_private_key_t *pri)
+static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc)
{
- chunk_t sigdata;
- u_char *pos;
- size_t siglen = 0;
-
- if (sc != NULL)
- {
- /* RSA signature is done on smartcard */
+ hasher_t *hasher;
+ u_char *pos;
+ u_char digest_buf[HASH_SIZE_SHA1];
+ chunk_t digest = chunk_from_buf(digest_buf);
+ chunk_t digest_info, sigdata;
+ size_t siglen = 0;
if (!scx_establish_context(sc) || !scx_login(sc))
{
- scx_release_context(sc);
- return empty_chunk;
+ scx_release_context(sc);
+ return chunk_empty;
}
siglen = scx_get_keylength(sc);
if (siglen == 0)
{
- plog("failed to get keylength from smartcard");
- scx_release_context(sc);
- return empty_chunk;
+ plog("failed to get keylength from smartcard");
+ scx_release_context(sc);
+ return chunk_empty;
}
DBG(DBG_CONTROL | DBG_CRYPT,
- DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
- , (int)sc->slot, sc->id)
+ DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
+ , (int)sc->slot, sc->id)
)
- pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (hasher == NULL)
+ {
+ return chunk_empty;
+ }
+ hasher->get_hash(hasher, tbs, digest_buf);
+ hasher->destroy(hasher);
+
+ /* according to PKCS#1 v2.1 digest must be packaged into
+ * an ASN.1 structure for encryption
+ */
+ digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , asn1_algorithmIdentifier(OID_SHA1)
+ , asn1_simple_object(ASN1_OCTET_STRING, digest));
+
+ pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
*pos++ = 0x00;
- scx_sign_hash(sc, digest.ptr, digest.len, pos, siglen);
+ scx_sign_hash(sc, digest_info.ptr, digest_info.len, pos, siglen);
+ free(digest_info.ptr);
+
if (!pkcs11_keep_state)
- scx_release_context(sc);
- }
- else
- {
- /* RSA signature is done in software */
- siglen = pri->pub.k;
- pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
- *pos++ = 0x00;
- sign_hash(pri, digest.ptr, digest.len, pos, siglen);
- }
- return sigdata;
+ {
+ scx_release_context(sc);
+ }
+ return sigdata;
}
-/*
- * build signature into ocsp request
- * gets built only if a request cert with
- * a corresponding private key is found
+/**
+ * build signature into ocsp request gets built only if a request cert
+ * with a corresponding private key is found
*/
-static chunk_t
-build_signature(chunk_t tbsRequest)
+static chunk_t build_signature(chunk_t tbsRequest)
{
- chunk_t sigdata, certs;
- chunk_t digest_info;
-
- u_char digest_buf[MAX_DIGEST_LEN];
- chunk_t digest_raw = { digest_buf, MAX_DIGEST_LEN };
-
- if (!compute_digest(tbsRequest, OID_SHA1, &digest_raw))
- return empty_chunk;
-
- /* according to PKCS#1 v2.1 digest must be packaged into
- * an ASN.1 structure for encryption
- */
- digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
- , ASN1_sha1_id
- , asn1_simple_object(ASN1_OCTET_STRING, digest_raw));
-
- /* generate the RSA signature */
- sigdata = generate_signature(digest_info
- , ocsp_requestor_sc
- , ocsp_requestor_pri);
- freeanychunk(digest_info);
-
- /* has the RSA signature generation been successful? */
- if (sigdata.ptr == NULL)
- return empty_chunk;
-
- /* include our certificate */
- certs = asn1_wrap(ASN1_CONTEXT_C_0, "m"
- , asn1_simple_object(ASN1_SEQUENCE
- , ocsp_requestor_cert->certificate
- )
- );
-
- /* build signature comprising algorithm, signature and cert */
- return asn1_wrap(ASN1_CONTEXT_C_0, "m"
- , asn1_wrap(ASN1_SEQUENCE, "cmm"
- , ASN1_sha1WithRSA_id
- , sigdata
- , certs
- )
- );
+ chunk_t sigdata, certs;
+
+ if (ocsp_requestor_sc != NULL)
+ {
+ /* RSA signature is done on smartcard */
+ sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc);
+ }
+ else
+ {
+ /* RSA signature is done in software */
+ sigdata = x509_build_signature(tbsRequest, OID_SHA1, ocsp_requestor_key,
+ TRUE);
+ }
+ if (sigdata.ptr == NULL)
+ {
+ return chunk_empty;
+ }
+
+ /* include our certificate */
+ certs = asn1_wrap(ASN1_CONTEXT_C_0, "m"
+ , asn1_simple_object(ASN1_SEQUENCE
+ , ocsp_requestor_cert->certificate
+ )
+ );
+
+ /* build signature comprising algorithm, signature and cert */
+ return asn1_wrap(ASN1_CONTEXT_C_0, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "cmm"
+ , asn1_algorithmIdentifier(OID_SHA1_WITH_RSA)
+ , sigdata
+ , certs
+ )
+ );
}
-/* build request (into requestList)
+/**
+ * Build request (into requestList)
* no singleRequestExtensions used
*/
-static chunk_t
-build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo)
+static chunk_t build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo)
{
- chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm"
- , ASN1_sha1_id
- , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID)
- , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID)
- , asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber));
+ chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm"
+ , asn1_algorithmIdentifier(OID_SHA1)
+ , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID)
+ , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID)
+ , asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber));
- return asn1_wrap(ASN1_SEQUENCE, "m", reqCert);
+ return asn1_wrap(ASN1_SEQUENCE, "m", reqCert);
}
-/*
+/**
* build requestList (into TBSRequest)
*/
-static chunk_t
-build_request_list(ocsp_location_t *location)
+static chunk_t build_request_list(ocsp_location_t *location)
{
- chunk_t requestList;
- request_list_t *reqs = NULL;
- ocsp_certinfo_t *certinfo = location->certinfo;
- u_char *pos;
-
- size_t datalen = 0;
-
- /* build content */
- while (certinfo != NULL)
- {
- /* build request for every certificate in list
- * and store them in a chained list
- */
- request_list_t *req = alloc_thing(request_list_t, "ocsp request");
+ chunk_t requestList;
+ request_list_t *reqs = NULL;
+ ocsp_certinfo_t *certinfo = location->certinfo;
+ u_char *pos;
- req->request = build_request(location, certinfo);
- req->next = reqs;
- reqs = req;
+ size_t datalen = 0;
- datalen += req->request.len;
- certinfo = certinfo->next;
- }
+ /* build content */
+ while (certinfo != NULL)
+ {
+ /* build request for every certificate in list
+ * and store them in a chained list
+ */
+ request_list_t *req = malloc_thing(request_list_t);
+
+ req->request = build_request(location, certinfo);
+ req->next = reqs;
+ reqs = req;
+
+ datalen += req->request.len;
+ certinfo = certinfo->next;
+ }
- pos = build_asn1_object(&requestList, ASN1_SEQUENCE
- , datalen);
+ pos = asn1_build_object(&requestList, ASN1_SEQUENCE, datalen);
- /* copy all in chained list, free list afterwards */
- while (reqs != NULL)
- {
- request_list_t *req = reqs;
+ /* copy all in chained list, free list afterwards */
+ while (reqs != NULL)
+ {
+ request_list_t *req = reqs;
- mv_chunk(&pos, req->request);
- reqs = reqs->next;
- pfree(req);
- }
+ mv_chunk(&pos, req->request);
+ reqs = reqs->next;
+ free(req);
+ }
- return requestList;
+ return requestList;
}
-/*
- * build requestorName (into TBSRequest)
+/**
+ * Build requestorName (into TBSRequest)
*/
-static chunk_t
-build_requestor_name(void)
+static chunk_t build_requestor_name(void)
{
- return asn1_wrap(ASN1_CONTEXT_C_1, "m"
- , asn1_simple_object(ASN1_CONTEXT_C_4
- , ocsp_requestor_cert->subject));
+ return asn1_wrap(ASN1_CONTEXT_C_1, "m"
+ , asn1_simple_object(ASN1_CONTEXT_C_4
+ , ocsp_requestor_cert->subject));
}
-/*
+/**
* build nonce extension (into requestExtensions)
*/
-static chunk_t
-build_nonce_extension(ocsp_location_t *location)
+static chunk_t build_nonce_extension(ocsp_location_t *location)
{
- /* generate a random nonce */
- location->nonce.ptr = alloc_bytes(NONCE_LENGTH, "ocsp nonce"),
- location->nonce.len = NONCE_LENGTH;
- get_rnd_bytes(location->nonce.ptr, NONCE_LENGTH);
-
- return asn1_wrap(ASN1_SEQUENCE, "cm"
- , ASN1_nonce_oid
- , asn1_simple_object(ASN1_OCTET_STRING, location->nonce));
+ rng_t *rng;
+
+ /* generate a random nonce */
+ location->nonce.ptr = malloc(NONCE_LENGTH),
+ location->nonce.len = NONCE_LENGTH;
+ rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ rng->get_bytes(rng, location->nonce.len, location->nonce.ptr);
+ rng->destroy(rng);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_nonce_oid
+ , asn1_simple_object(ASN1_OCTET_STRING, location->nonce));
}
-/*
- * build requestExtensions (into TBSRequest)
+/**
+ * Build requestExtensions (into TBSRequest)
*/
-static chunk_t
-build_request_ext(ocsp_location_t *location)
+static chunk_t build_request_ext(ocsp_location_t *location)
{
- return asn1_wrap(ASN1_CONTEXT_C_2, "m"
- , asn1_wrap(ASN1_SEQUENCE, "mm"
- , build_nonce_extension(location)
- , asn1_wrap(ASN1_SEQUENCE, "cc"
- , ASN1_response_oid
- , ASN1_response_content
- )
- )
- );
+ return asn1_wrap(ASN1_CONTEXT_C_2, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "mm"
+ , build_nonce_extension(location)
+ , asn1_wrap(ASN1_SEQUENCE, "cc"
+ , ASN1_response_oid
+ , ASN1_response_content
+ )
+ )
+ );
}
-/*
- * build TBSRequest (into OCSPRequest)
+/**
+ * Build TBSRequest (into OCSPRequest)
*/
-static chunk_t
-build_tbs_request(ocsp_location_t *location, bool has_requestor_cert)
+static chunk_t build_tbs_request(ocsp_location_t *location, bool has_requestor_cert)
{
- /* version is skipped since the default is ok */
- return asn1_wrap(ASN1_SEQUENCE, "mmm"
- , (has_requestor_cert)
- ? build_requestor_name()
- : empty_chunk
- , build_request_list(location)
- , build_request_ext(location));
+ /* version is skipped since the default is ok */
+ return asn1_wrap(ASN1_SEQUENCE, "mmm"
+ , (has_requestor_cert)
+ ? build_requestor_name()
+ : chunk_empty
+ , build_request_list(location)
+ , build_request_ext(location));
}
-/* assembles an ocsp request to given location
+/**
+ * Assembles an ocsp request to given location
* and sets nonce field in location to the sent nonce
*/
-chunk_t
-build_ocsp_request(ocsp_location_t *location)
+chunk_t build_ocsp_request(ocsp_location_t *location)
{
- bool has_requestor_cert;
- chunk_t tbsRequest, signature;
- char buf[BUF_LEN];
-
- DBG(DBG_CONTROL,
- DBG_log("assembling ocsp request");
- dntoa(buf, BUF_LEN, location->issuer);
- DBG_log("issuer: '%s'", buf);
- if (location->authKeyID.ptr != NULL)
- {
- datatot(location->authKeyID.ptr, location->authKeyID.len, ':'
- , buf, BUF_LEN);
- DBG_log("authkey: %s", buf);
- }
- )
- lock_certs_and_keys("build_ocsp_request");
+ bool has_requestor_cert;
+ chunk_t tbsRequest, signature;
+ char buf[BUF_LEN];
- /* looks for requestor cert and matching private key */
- has_requestor_cert = get_ocsp_requestor_cert(location);
+ DBG(DBG_CONTROL,
+ DBG_log("assembling ocsp request");
+ dntoa(buf, BUF_LEN, location->issuer);
+ DBG_log("issuer: '%s'", buf);
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+ lock_certs_and_keys("build_ocsp_request");
+
+ /* looks for requestor cert and matching private key */
+ has_requestor_cert = get_ocsp_requestor_cert(location);
- /* build content */
- tbsRequest = build_tbs_request(location, has_requestor_cert);
+ /* build content */
+ tbsRequest = build_tbs_request(location, has_requestor_cert);
- /* sign tbsReuqest */
- signature = (has_requestor_cert)? build_signature(tbsRequest)
- : empty_chunk;
+ /* sign tbsReuqest */
+ signature = (has_requestor_cert)? build_signature(tbsRequest)
+ : chunk_empty;
- unlock_certs_and_keys("build_ocsp_request");
+ unlock_certs_and_keys("build_ocsp_request");
- return asn1_wrap(ASN1_SEQUENCE, "mm"
- , tbsRequest
- , signature);
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , tbsRequest
+ , signature);
}
-/*
- * check if the OCSP response has a valid signature
+/**
+ * Check if the OCSP response has a valid signature
*/
-static bool
-valid_ocsp_response(response_t *res)
+static bool valid_ocsp_response(response_t *res)
{
- int pathlen;
- x509cert_t *authcert;
+ int pathlen;
+ x509cert_t *authcert;
- lock_authcert_list("valid_ocsp_response");
+ lock_authcert_list("valid_ocsp_response");
- authcert = get_authcert(res->responder_id_name, empty_chunk
- , res->responder_id_key, AUTH_OCSP | AUTH_CA);
-
- if (authcert == NULL)
- {
- plog("no matching ocsp signer cert found");
- unlock_authcert_list("valid_ocsp_response");
- return FALSE;
- }
- DBG(DBG_CONTROL,
- DBG_log("ocsp signer cert found")
- )
-
- if (!check_signature(res->tbs, res->signature, res->algorithm
- , res->algorithm, authcert))
- {
- plog("signature of ocsp response is invalid");
- unlock_authcert_list("valid_ocsp_response");
- return FALSE;
- }
- DBG(DBG_CONTROL,
- DBG_log("signature of ocsp response is valid")
- )
-
-
- for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
- {
- u_char buf[BUF_LEN];
- err_t ugh = NULL;
- time_t until;
-
- x509cert_t *cert = authcert;
-
- DBG(DBG_CONTROL,
- dntoa(buf, BUF_LEN, cert->subject);
- DBG_log("subject: '%s'",buf);
- dntoa(buf, BUF_LEN, cert->issuer);
- DBG_log("issuer: '%s'",buf);
- if (cert->authKeyID.ptr != NULL)
- {
- datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
- , buf, BUF_LEN);
- DBG_log("authkey: %s", buf);
- }
- )
-
- ugh = check_validity(authcert, &until);
-
- if (ugh != NULL)
- {
- plog("%s", ugh);
- unlock_authcert_list("valid_ocsp_response");
- return FALSE;
- }
-
- DBG(DBG_CONTROL,
- DBG_log("certificate is valid")
- )
-
- authcert = get_authcert(cert->issuer, cert->authKeySerialNumber
- , cert->authKeyID, AUTH_CA);
+ authcert = get_authcert(res->responder_id_name, chunk_empty
+ , res->responder_id_key, AUTH_OCSP | AUTH_CA);
if (authcert == NULL)
{
- plog("issuer cacert not found");
- unlock_authcert_list("valid_ocsp_response");
- return FALSE;
+ plog("no matching ocsp signer cert found");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
}
DBG(DBG_CONTROL,
- DBG_log("issuer cacert found")
+ DBG_log("ocsp signer cert found")
)
- if (!check_signature(cert->tbsCertificate, cert->signature
- , cert->algorithm, cert->algorithm, authcert))
+ if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert))
{
- plog("certificate signature is invalid");
- unlock_authcert_list("valid_ocsp_response");
- return FALSE;
+ plog("signature of ocsp response is invalid");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
}
DBG(DBG_CONTROL,
- DBG_log("certificate signature is valid")
+ DBG_log("signature of ocsp response is valid")
)
- /* check if cert is self-signed */
- if (same_dn(cert->issuer, cert->subject))
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
{
- DBG(DBG_CONTROL,
- DBG_log("reached self-signed root ca")
- )
- unlock_authcert_list("valid_ocsp_response");
- return TRUE;
+ u_char buf[BUF_LEN];
+ err_t ugh = NULL;
+ time_t until;
+
+ x509cert_t *cert = authcert;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("subject: '%s'",buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+
+ ugh = check_validity(authcert, &until);
+
+ if (ugh != NULL)
+ {
+ plog("%s", ugh);
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is valid")
+ )
+
+ authcert = get_authcert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, AUTH_CA);
+
+ if (authcert == NULL)
+ {
+ plog("issuer cacert not found");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found")
+ )
+
+ if (!x509_check_signature(cert->tbsCertificate, cert->signature,
+ cert->algorithm, authcert))
+ {
+ plog("certificate signature is invalid");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate signature is valid")
+ )
+
+ /* check if cert is self-signed */
+ if (same_dn(cert->issuer, cert->subject))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("reached self-signed root ca")
+ )
+ unlock_authcert_list("valid_ocsp_response");
+ return TRUE;
+ }
}
- }
- plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
- unlock_authcert_list("valid_ocsp_response");
- return FALSE;
+ plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
}
-/*
- * parse a basic OCSP response
+/**
+ * Parse a basic OCSP response
*/
-static bool
-parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
+static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
{
- asn1_ctx_t ctx;
- bool critical;
- chunk_t object;
- u_int level, version;
- u_char buf[BUF_LEN];
- int objectID = 0;
- int extn_oid = OID_UNKNOWN;
-
- asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
-
- while (objectID < BASIC_RESPONSE_ROOF)
- {
- if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx))
- return FALSE;
-
- switch (objectID)
+ asn1_parser_t *parser;
+ chunk_t object;
+ u_int version;
+ u_char buf[BUF_LEN];
+ int objectID;
+ int extn_oid = OID_UNKNOWN;
+ bool success = FALSE;
+ bool critical;
+
+ parser = asn1_parser_create(basicResponseObjects, blob);
+ parser->set_top_level(parser, level0);
+
+ while (parser->iterate(parser, &objectID, &object))
{
- case BASIC_RESPONSE_TBS_DATA:
- res->tbs = object;
- break;
- case BASIC_RESPONSE_VERSION:
- version = (object.len)? (1 + (u_int)*object.ptr) : 1;
- if (version != OCSP_BASIC_RESPONSE_VERSION)
- {
- plog("wrong ocsp basic response version (version= %i)", version);
- return FALSE;
- }
- break;
- case BASIC_RESPONSE_ID_BY_NAME:
- res->responder_id_name = object;
- DBG(DBG_PARSING,
- dntoa(buf, BUF_LEN, object);
- DBG_log(" '%s'",buf)
- )
- break;
- case BASIC_RESPONSE_ID_BY_KEY:
- res->responder_id_key = object;
- break;
- case BASIC_RESPONSE_PRODUCED_AT:
- res->produced_at = asn1totime(&object, ASN1_GENERALIZEDTIME);
- break;
- case BASIC_RESPONSE_RESPONSES:
- res->responses = object;
- break;
- case BASIC_RESPONSE_EXT_ID:
- extn_oid = known_oid(object);
- break;
- case BASIC_RESPONSE_CRITICAL:
- critical = object.len && *object.ptr;
- DBG(DBG_PARSING,
- DBG_log(" %s",(critical)?"TRUE":"FALSE");
- )
- break;
- case BASIC_RESPONSE_EXT_VALUE:
- if (extn_oid == OID_NONCE)
- res->nonce = object;
- break;
- case BASIC_RESPONSE_ALGORITHM:
- res->algorithm = parse_algorithmIdentifier(object, level+1, NULL);
- break;
- case BASIC_RESPONSE_SIGNATURE:
- res->signature = object;
- break;
- case BASIC_RESPONSE_CERTIFICATE:
- {
- chunk_t blob;
- x509cert_t *cert = alloc_thing(x509cert_t, "ocspcert");
-
- clonetochunk(blob, object.ptr, object.len, "ocspcert blob");
- *cert = empty_x509cert;
-
- if (parse_x509cert(blob, level+1, cert)
- && cert->isOcspSigner
- && trust_authcert_candidate(cert, NULL))
+ switch (objectID)
{
- add_authcert(cert, AUTH_OCSP);
- }
- else
- {
- DBG(DBG_CONTROL | DBG_PARSING,
- DBG_log("embedded ocsp certificate rejected")
- )
- free_x509cert(cert);
+ case BASIC_RESPONSE_TBS_DATA:
+ res->tbs = object;
+ break;
+ case BASIC_RESPONSE_VERSION:
+ version = (object.len)? (1 + (u_int)*object.ptr) : 1;
+ if (version != OCSP_BASIC_RESPONSE_VERSION)
+ {
+ plog("wrong ocsp basic response version (version= %i)", version);
+ goto end;
+ }
+ break;
+ case BASIC_RESPONSE_ID_BY_NAME:
+ res->responder_id_name = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case BASIC_RESPONSE_ID_BY_KEY:
+ res->responder_id_key = object;
+ break;
+ case BASIC_RESPONSE_PRODUCED_AT:
+ res->produced_at = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case BASIC_RESPONSE_RESPONSES:
+ res->responses = object;
+ break;
+ case BASIC_RESPONSE_EXT_ID:
+ extn_oid = asn1_known_oid(object);
+ break;
+ case BASIC_RESPONSE_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ break;
+ case BASIC_RESPONSE_EXT_VALUE:
+ if (extn_oid == OID_NONCE)
+ res->nonce = object;
+ break;
+ case BASIC_RESPONSE_ALGORITHM:
+ res->algorithm = asn1_parse_algorithmIdentifier(object,
+ parser->get_level(parser)+1, NULL);
+ break;
+ case BASIC_RESPONSE_SIGNATURE:
+ res->signature = object;
+ break;
+ case BASIC_RESPONSE_CERTIFICATE:
+ {
+ chunk_t blob = chunk_clone(object);
+ x509cert_t *cert = malloc_thing(x509cert_t);
+
+ *cert = empty_x509cert;
+
+ if (parse_x509cert(blob, parser->get_level(parser)+1, cert)
+ && cert->isOcspSigner
+ && trust_authcert_candidate(cert, NULL))
+ {
+ add_authcert(cert, AUTH_OCSP);
+ }
+ else
+ {
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("embedded ocsp certificate rejected")
+ )
+ free_x509cert(cert);
+ }
+ }
+ break;
}
- }
- break;
}
- objectID++;
- }
- return TRUE;
+ success = parser->success(parser);
+
+end:
+ parser->destroy(parser);
+ return success;
+
}
-/*
- * parse an ocsp response and return the result as a response_t struct
+/**
+ * Parse an ocsp response and return the result as a response_t struct
*/
-static response_status
-parse_ocsp_response(chunk_t blob, response_t * res)
+static response_status parse_ocsp_response(chunk_t blob, response_t * res)
{
- asn1_ctx_t ctx;
- chunk_t object;
- u_int level;
- int objectID = 0;
- int ocspResponseType = OID_UNKNOWN;
- response_status rStatus = STATUS_INTERNALERROR;
-
- asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
-
- while (objectID < OCSP_RESPONSE_ROOF)
- {
- if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx))
- return STATUS_INTERNALERROR;
-
- switch (objectID) {
- case OCSP_RESPONSE_STATUS:
- rStatus = (response_status) *object.ptr;
-
- switch (rStatus)
- {
- case STATUS_SUCCESSFUL:
- break;
- case STATUS_MALFORMEDREQUEST:
- case STATUS_INTERNALERROR:
- case STATUS_TRYLATER:
- case STATUS_SIGREQUIRED:
- case STATUS_UNAUTHORIZED:
- plog("ocsp response: server said '%s'"
- , response_status_names[rStatus]);
- return rStatus;
- default:
- return STATUS_INTERNALERROR;
- }
- break;
- case OCSP_RESPONSE_TYPE:
- ocspResponseType = known_oid(object);
- break;
- case OCSP_RESPONSE:
- {
- switch (ocspResponseType) {
- case OID_BASIC:
- if (!parse_basic_ocsp_response(object, level+1, res))
- return STATUS_INTERNALERROR;
- break;
- default:
- DBG(DBG_CONTROL,
- DBG_log("ocsp response is not of type BASIC");
- DBG_dump_chunk("ocsp response OID: ", object);
- )
- return STATUS_INTERNALERROR;
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID;
+ int ocspResponseType = OID_UNKNOWN;
+ bool success = FALSE;
+ response_status rStatus = STATUS_INTERNALERROR;
+
+ parser = asn1_parser_create(ocspResponseObjects, blob);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID) {
+ case OCSP_RESPONSE_STATUS:
+ rStatus = (response_status) *object.ptr;
+
+ switch (rStatus)
+ {
+ case STATUS_SUCCESSFUL:
+ break;
+ case STATUS_MALFORMEDREQUEST:
+ case STATUS_INTERNALERROR:
+ case STATUS_TRYLATER:
+ case STATUS_SIGREQUIRED:
+ case STATUS_UNAUTHORIZED:
+ plog("ocsp response: server said '%s'"
+ , response_status_names[rStatus]);
+ goto end;
+ default:
+ goto end;
+ }
+ break;
+ case OCSP_RESPONSE_TYPE:
+ ocspResponseType = asn1_known_oid(object);
+ break;
+ case OCSP_RESPONSE:
+ {
+ switch (ocspResponseType) {
+ case OID_BASIC:
+ success = parse_basic_ocsp_response(object,
+ parser->get_level(parser)+1, res);
+ break;
+ default:
+ DBG(DBG_CONTROL,
+ DBG_log("ocsp response is not of type BASIC");
+ DBG_dump_chunk("ocsp response OID: ", object);
+ )
+ goto end;
+ }
+ }
+ break;
}
- }
- break;
}
- objectID++;
- }
- return rStatus;
+ success &= parser->success(parser);
+
+end:
+ parser->destroy(parser);
+ return rStatus;
}
-/*
- * parse a basic OCSP response
+/**
+ * Parse a basic OCSP response
*/
-static bool
-parse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres)
+static bool parse_ocsp_single_response(chunk_t blob, int level0,
+ single_response_t *sres)
{
- u_int level, extn_oid;
- asn1_ctx_t ctx;
- bool critical;
- chunk_t object;
- int objectID = 0;
-
- asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+ asn1_parser_t *parser;
+ chunk_t object;
+ u_int extn_oid;
+ int objectID;
+ bool critical;
+ bool success = FALSE;
- while (objectID < SINGLE_RESPONSE_ROOF)
- {
- if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx))
- return FALSE;
+ parser = asn1_parser_create(singleResponseObjects, blob);
+ parser->set_top_level(parser, level0);
- switch (objectID)
+ while (parser->iterate(parser, &objectID, &object))
{
- case SINGLE_RESPONSE_ALGORITHM:
- sres->hash_algorithm = parse_algorithmIdentifier(object, level+1, NULL);
- break;
- case SINGLE_RESPONSE_ISSUER_NAME_HASH:
- sres->issuer_name_hash = object;
- break;
- case SINGLE_RESPONSE_ISSUER_KEY_HASH:
- sres->issuer_key_hash = object;
- break;
- case SINGLE_RESPONSE_SERIAL_NUMBER:
- sres->serialNumber = object;
- break;
- case SINGLE_RESPONSE_CERT_STATUS_GOOD:
- sres->status = CERT_GOOD;
- break;
- case SINGLE_RESPONSE_CERT_STATUS_REVOKED:
- sres->status = CERT_REVOKED;
- break;
- case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME:
- sres->revocationTime = asn1totime(&object, ASN1_GENERALIZEDTIME);
- break;
- case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON:
- sres->revocationReason = (object.len == 1)
- ? *object.ptr : REASON_UNSPECIFIED;
- break;
- case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
- sres->status = CERT_UNKNOWN;
- break;
- case SINGLE_RESPONSE_THIS_UPDATE:
- sres->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
- break;
- case SINGLE_RESPONSE_NEXT_UPDATE:
- sres->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
- break;
- case SINGLE_RESPONSE_EXT_ID:
- extn_oid = known_oid(object);
- break;
- case SINGLE_RESPONSE_CRITICAL:
- critical = object.len && *object.ptr;
- DBG(DBG_PARSING,
- DBG_log(" %s",(critical)?"TRUE":"FALSE");
- )
- case SINGLE_RESPONSE_EXT_VALUE:
- break;
+ switch (objectID)
+ {
+ case SINGLE_RESPONSE_ALGORITHM:
+ sres->hash_algorithm = asn1_parse_algorithmIdentifier(object,
+ parser->get_level(parser)+1, NULL);
+ break;
+ case SINGLE_RESPONSE_ISSUER_NAME_HASH:
+ sres->issuer_name_hash = object;
+ break;
+ case SINGLE_RESPONSE_ISSUER_KEY_HASH:
+ sres->issuer_key_hash = object;
+ break;
+ case SINGLE_RESPONSE_SERIAL_NUMBER:
+ sres->serialNumber = object;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_GOOD:
+ sres->status = CERT_GOOD;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_REVOKED:
+ sres->status = CERT_REVOKED;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME:
+ sres->revocationTime = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON:
+ sres->revocationReason = (object.len == 1)
+ ? *object.ptr : REASON_UNSPECIFIED;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
+ sres->status = CERT_UNKNOWN;
+ break;
+ case SINGLE_RESPONSE_THIS_UPDATE:
+ sres->thisUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_NEXT_UPDATE:
+ sres->nextUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_EXT_ID:
+ extn_oid = asn1_known_oid(object);
+ break;
+ case SINGLE_RESPONSE_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ case SINGLE_RESPONSE_EXT_VALUE:
+ break;
+ }
}
- objectID++;
- }
- return TRUE;
+ success = parser->success(parser);
+ parser->destroy(parser);
+ return success;
}
-/*
- * add an ocsp location to a chained list
+/**
+ * Add an ocsp location to a chained list
*/
-ocsp_location_t*
-add_ocsp_location(const ocsp_location_t *loc, ocsp_location_t **chain)
+ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc,
+ ocsp_location_t **chain)
{
- ocsp_location_t *location = alloc_thing(ocsp_location_t, "ocsp location");
-
- /* unshare location fields */
- clonetochunk(location->issuer
- , loc->issuer.ptr, loc->issuer.len
- , "ocsp issuer");
-
- clonetochunk(location->authNameID
- , loc->authNameID.ptr, loc->authNameID.len
- , "ocsp authNameID");
-
- if (loc->authKeyID.ptr == NULL)
- location->authKeyID = empty_chunk;
- else
- clonetochunk(location->authKeyID
- , loc->authKeyID.ptr, loc->authKeyID.len
- , "ocsp authKeyID");
-
- if (loc->authKeySerialNumber.ptr == NULL)
- location->authKeySerialNumber = empty_chunk;
- else
- clonetochunk(location->authKeySerialNumber
- , loc->authKeySerialNumber.ptr, loc->authKeySerialNumber.len
- , "ocsp authKeySerialNumber");
-
- clonetochunk(location->uri
- , loc->uri.ptr, loc->uri.len
- , "ocsp uri");
-
- location->certinfo = NULL;
-
- /* insert new ocsp location in front of chain */
- location->next = *chain;
- *chain = location;
-
- DBG(DBG_CONTROL,
- DBG_log("new ocsp location added")
- )
-
- return location;
+ ocsp_location_t *location = malloc_thing(ocsp_location_t);
+
+ /* unshare location fields */
+ location->issuer = chunk_clone(loc->issuer);
+ location->authNameID = chunk_clone(loc->authNameID);
+ location->authKeyID = chunk_clone(loc->authKeyID);
+ location->authKeySerialNumber = chunk_clone(loc->authKeySerialNumber);
+ location->uri = chunk_clone(loc->uri);
+ location->certinfo = NULL;
+
+ /* insert new ocsp location in front of chain */
+ location->next = *chain;
+ *chain = location;
+
+ DBG(DBG_CONTROL,
+ DBG_log("new ocsp location added")
+ )
+
+ return location;
}
-/*
+/**
* add a certinfo struct to a chained list
*/
-void
-add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, ocsp_location_t **chain
- , bool request)
+void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info,
+ ocsp_location_t **chain, bool request)
{
- ocsp_location_t *location;
- ocsp_certinfo_t *certinfo, **certinfop;
- char buf[BUF_LEN];
- time_t now;
- int cmp = -1;
-
- location = get_ocsp_location(loc, *chain);
- if (location == NULL)
- location = add_ocsp_location(loc, chain);
-
- /* traverse list of certinfos in increasing order */
- certinfop = &location->certinfo;
- certinfo = *certinfop;
-
- while (certinfo != NULL)
- {
- cmp = cmp_chunk(info->serialNumber, certinfo->serialNumber);
- if (cmp <= 0)
- break;
- certinfop = &certinfo->next;
+ ocsp_location_t *location;
+ ocsp_certinfo_t *certinfo, **certinfop;
+ char buf[BUF_LEN];
+ time_t now;
+ int cmp = -1;
+
+ location = get_ocsp_location(loc, *chain);
+ if (location == NULL)
+ {
+ location = add_ocsp_location(loc, chain);
+ }
+
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
certinfo = *certinfop;
- }
-
- if (cmp != 0)
- {
- /* add a new certinfo entry */
- ocsp_certinfo_t *cnew = alloc_thing(ocsp_certinfo_t, "ocsp certinfo");
- clonetochunk(cnew->serialNumber, info->serialNumber.ptr
- , info->serialNumber.len, "serialNumber");
- cnew->next = certinfo;
- *certinfop = cnew;
- certinfo = cnew;
- }
-
- DBG(DBG_CONTROL,
- datatot(info->serialNumber.ptr, info->serialNumber.len, ':'
- , buf, BUF_LEN);
- DBG_log("ocsp %s for serial %s %s"
- , request?"fetch request":"certinfo"
- , buf
- , (cmp == 0)? (request?"already exists":"updated"):"added")
- )
-
- time(&now);
-
- if (request)
- {
- certinfo->status = CERT_UNDEFINED;
-
+
+ while (certinfo != NULL)
+ {
+ cmp = chunk_compare(info->serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
if (cmp != 0)
- certinfo->thisUpdate = now;
-
- certinfo->nextUpdate = UNDEFINED_TIME;
- }
- else
- {
- certinfo->status = info->status;
- certinfo->revocationTime = info->revocationTime;
- certinfo->revocationReason = info->revocationReason;
-
- certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)?
- info->thisUpdate : now;
+ {
+ /* add a new certinfo entry */
+ ocsp_certinfo_t *cnew = malloc_thing(ocsp_certinfo_t);
+
+ cnew->serialNumber = chunk_clone(info->serialNumber);
+ cnew->next = certinfo;
+ *certinfop = cnew;
+ certinfo = cnew;
+ }
+
+ DBG(DBG_CONTROL,
+ datatot(info->serialNumber.ptr, info->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("ocsp %s for serial %s %s"
+ , request?"fetch request":"certinfo"
+ , buf
+ , (cmp == 0)? (request?"already exists":"updated"):"added")
+ )
+
+ time(&now);
+
+ if (request)
+ {
+ certinfo->status = CERT_UNDEFINED;
+
+ if (cmp != 0)
+ {
+ certinfo->thisUpdate = now;
+ }
+ certinfo->nextUpdate = UNDEFINED_TIME;
+ }
+ else
+ {
+ certinfo->status = info->status;
+ certinfo->revocationTime = info->revocationTime;
+ certinfo->revocationReason = info->revocationReason;
+
+ certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)?
+ info->thisUpdate : now;
- certinfo->once = (info->nextUpdate == UNDEFINED_TIME);
+ certinfo->once = (info->nextUpdate == UNDEFINED_TIME);
- certinfo->nextUpdate = (certinfo->once)?
- (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate;
- }
+ certinfo->nextUpdate = (certinfo->once)?
+ (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate;
+ }
}
-/*
- * process received ocsp single response and add it to ocsp cache
+/**
+ * Process received ocsp single response and add it to ocsp cache
*/
-static void
-process_single_response(ocsp_location_t *location, single_response_t *sres)
+static void process_single_response(ocsp_location_t *location,
+ single_response_t *sres)
{
- ocsp_certinfo_t *certinfo, **certinfop;
- int cmp = -1;
-
- if (sres->hash_algorithm != OID_SHA1)
- {
- plog("only SHA-1 hash supported in OCSP single response");
- return;
- }
- if (!(same_chunk(sres->issuer_name_hash, location->authNameID)
- && same_chunk(sres->issuer_key_hash, location->authKeyID)))
- {
- plog("ocsp single response has wrong issuer");
- return;
- }
-
- /* traverse list of certinfos in increasing order */
- certinfop = &location->certinfo;
- certinfo = *certinfop;
-
- while (certinfo != NULL)
- {
- cmp = cmp_chunk(sres->serialNumber, certinfo->serialNumber);
- if (cmp <= 0)
- break;
- certinfop = &certinfo->next;
+ ocsp_certinfo_t *certinfo, **certinfop;
+ int cmp = -1;
+
+ if (sres->hash_algorithm != OID_SHA1)
+ {
+ plog("only SHA-1 hash supported in OCSP single response");
+ return;
+ }
+ if (!(chunk_equals(sres->issuer_name_hash, location->authNameID)
+ && chunk_equals(sres->issuer_key_hash, location->authKeyID)))
+ {
+ plog("ocsp single response has wrong issuer");
+ return;
+ }
+
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
certinfo = *certinfop;
- }
-
- if (cmp != 0)
- {
- plog("received unrequested cert status from ocsp server");
- return;
- }
-
- /* unlink cert from ocsp fetch request list */
- *certinfop = certinfo->next;
-
- /* update certinfo using the single response information */
- certinfo->thisUpdate = sres->thisUpdate;
- certinfo->nextUpdate = sres->nextUpdate;
- certinfo->status = sres->status;
- certinfo->revocationTime = sres->revocationTime;
- certinfo->revocationReason = sres->revocationReason;
-
- /* add or update certinfo in ocsp cache */
- lock_ocsp_cache("process_single_response");
- add_certinfo(location, certinfo, &ocsp_cache, FALSE);
- unlock_ocsp_cache("process_single_response");
-
- /* free certinfo unlinked from ocsp fetch request list */
- free_certinfo(certinfo);
+ while (certinfo != NULL)
+ {
+ cmp = chunk_compare(sres->serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
+ if (cmp != 0)
+ {
+ plog("received unrequested cert status from ocsp server");
+ return;
+ }
+
+ /* unlink cert from ocsp fetch request list */
+ *certinfop = certinfo->next;
+
+ /* update certinfo using the single response information */
+ certinfo->thisUpdate = sres->thisUpdate;
+ certinfo->nextUpdate = sres->nextUpdate;
+ certinfo->status = sres->status;
+ certinfo->revocationTime = sres->revocationTime;
+ certinfo->revocationReason = sres->revocationReason;
+
+ /* add or update certinfo in ocsp cache */
+ lock_ocsp_cache("process_single_response");
+ add_certinfo(location, certinfo, &ocsp_cache, FALSE);
+ unlock_ocsp_cache("process_single_response");
+
+ /* free certinfo unlinked from ocsp fetch request list */
+ free_certinfo(certinfo);
}
-/*
- * parse and verify ocsp response and update the ocsp cache
+/**
+ * Parse and verify ocsp response and update the ocsp cache
*/
-void
-parse_ocsp(ocsp_location_t *location, chunk_t blob)
+void parse_ocsp(ocsp_location_t *location, chunk_t blob)
{
- response_t res = empty_response;
-
- /* parse the ocsp response without looking at the single responses yet */
- response_status status = parse_ocsp_response(blob, &res);
-
- if (status != STATUS_SUCCESSFUL)
- {
- plog("error in ocsp response");
- return;
- }
- /* check if there was a nonce in the request */
- if (location->nonce.ptr != NULL && res.nonce.ptr == NULL)
- {
- plog("ocsp response contains no nonce, replay attack possible");
- }
- /* check if the nonce is identical */
- if (res.nonce.ptr != NULL && !same_chunk(res.nonce, location->nonce))
- {
- plog("invalid nonce in ocsp response");
- return;
- }
- /* check if the response is signed by a trusted key */
- if (!valid_ocsp_response(&res))
- {
- plog("invalid ocsp response");
- return;
- }
- DBG(DBG_CONTROL,
- DBG_log("valid ocsp response")
- )
-
- /* now parse the single responses one at a time */
- {
- u_int level;
- asn1_ctx_t ctx;
- chunk_t object;
- int objectID = 0;
+ response_t res = empty_response;
- asn1_init(&ctx, res.responses, 0, FALSE, DBG_RAW);
+ /* parse the ocsp response without looking at the single responses yet */
+ response_status status = parse_ocsp_response(blob, &res);
- while (objectID < RESPONSES_ROOF)
+ if (status != STATUS_SUCCESSFUL)
+ {
+ plog("error in ocsp response");
+ return;
+ }
+ /* check if there was a nonce in the request */
+ if (location->nonce.ptr != NULL && res.nonce.ptr == NULL)
+ {
+ plog("ocsp response contains no nonce, replay attack possible");
+ }
+ /* check if the nonce is identical */
+ if (res.nonce.ptr != NULL && !chunk_equals(res.nonce, location->nonce))
+ {
+ plog("invalid nonce in ocsp response");
+ return;
+ }
+ /* check if the response is signed by a trusted key */
+ if (!valid_ocsp_response(&res))
{
- if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx))
+ plog("invalid ocsp response");
return;
-
- if (objectID == RESPONSES_SINGLE_RESPONSE)
- {
- single_response_t sres = empty_single_response;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("valid ocsp response")
+ )
- if (parse_ocsp_single_response(object, level+1, &sres))
+ /* now parse the single responses one at a time */
+ {
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID;
+
+ parser = asn1_parser_create(responsesObjects, res.responses);
+
+ while (parser->iterate(parser, &objectID, &object))
{
- process_single_response(location, &sres);
+ if (objectID == RESPONSES_SINGLE_RESPONSE)
+ {
+ single_response_t sres = empty_single_response;
+
+ if (!parse_ocsp_single_response(object,
+ parser->get_level(parser)+1, &sres))
+ {
+ goto end;
+ }
+ process_single_response(location, &sres);
+ }
}
- }
- objectID++;
+end:
+ parser->destroy(parser);
}
- }
}