/*
- * Copyright (C) 2022 Andreas Steffen, strongSec GmbH
+ * Copyright (C) 2022-2023 Andreas Steffen, strongSec GmbH
*
* Copyright (C) secunet Security Networks AG
*
#include <credentials/certificates/x509.h>
#include <credentials/certificates/crl.h>
+#include <credentials/certificates/ocsp_request.h>
#include <credentials/certificates/ocsp_response.h>
+#include <credentials/certificates/ocsp_single_response.h>
#include <credentials/certificates/ac.h>
#include <time.h>
return ocsp_req;
}
+/**
+ * Parse an ASN.1 encoded OCSP request
+ */
+static certificate_t* parse_ocsp_request(chunk_t encoding)
+{
+ certificate_t *ocsp_req;
+
+ ocsp_req = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
+ BUILD_BLOB_ASN1_DER, encoding,
+ BUILD_END);
+ ck_assert(ocsp_req);
+
+ return ocsp_req;
+}
+
+/**
+ * Create an OCSP response based on an OCSP request
+ */
+static certificate_t* create_ocsp_response(ocsp_request_t *ocsp_request,
+ cert_validation_t status,
+ certificate_t *cert)
+{
+ private_key_t *privkey;
+ certificate_t *ocsp_rsp;
+ ocsp_status_t ocsp_status = OCSP_SUCCESSFUL;
+ ocsp_single_response_t *response;
+ chunk_t issuerNameHash, issuerKeyHash, serialNumber, nonce;
+ hash_algorithm_t hashAlgorithm;
+ linked_list_t *responses = linked_list_create();
+ enumerator_t *enumerator;
+
+ privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+ BUILD_BLOB_ASN1_DER, chunk_from_thing(keydata),
+ BUILD_END);
+ ck_assert(privkey);
+
+ /* generate OCSP single response */
+ enumerator = ocsp_request->create_request_enumerator(ocsp_request);
+ ck_assert(enumerator->enumerate(enumerator, &hashAlgorithm, &issuerNameHash,
+ &issuerKeyHash, &serialNumber));
+ response = ocsp_single_response_create();
+ response->hashAlgorithm = hashAlgorithm;
+ response->issuerNameHash = chunk_clone(issuerNameHash);
+ response->issuerKeyHash = chunk_clone(issuerKeyHash);
+ response->serialNumber = chunk_clone(serialNumber);
+ response->thisUpdate = time(NULL);
+ response->status = status;
+ if (status == VALIDATION_REVOKED)
+ {
+ response->revocationReason = CRL_REASON_KEY_COMPROMISE;
+ response->revocationTime = time(NULL);
+ }
+ responses->insert_last(responses, response);
+ enumerator->destroy(enumerator);
+
+ nonce = ocsp_request->get_nonce(ocsp_request);
+
+ /* generate OCSP response */
+ enumerator = responses->create_enumerator(responses);
+ ocsp_rsp = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+ CERT_X509_OCSP_RESPONSE,
+ BUILD_OCSP_STATUS, ocsp_status,
+ BUILD_OCSP_RESPONSES, enumerator,
+ BUILD_SIGNING_KEY, privkey,
+ BUILD_SIGNING_CERT, cert,
+ BUILD_NONCE, nonce,
+ BUILD_END);
+ enumerator->destroy(enumerator);
+
+ ck_assert(ocsp_rsp);
+
+ privkey->destroy(privkey);
+ responses->destroy_offset(responses, offsetof(ocsp_single_response_t, destroy));
+
+ return ocsp_rsp;
+}
+
/**
* Parse an ASN.1 encoded OCSP response
*/
chunk_from_chars(0x05,0x00,0xff,0xff,0xff,0xff) },
};
-static chunk_t ocsp_responses[] = {
- chunk_from_chars(
- 0x30,0x82,0x01,0x85,0x0a,0x01,0x00,0xa0,0x82,0x01,0x7e,0x30,0x82,0x01,0x7a,0x06,
- 0x09,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x01,0x04,0x82,0x01,0x6b,0x30,0x82,
- 0x01,0x67,0x30,0x81,0xd1,0xa1,0x33,0x30,0x31,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,
- 0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0a,0x13,
- 0x0a,0x73,0x74,0x72,0x6f,0x6e,0x67,0x53,0x77,0x61,0x6e,0x31,0x0d,0x30,0x0b,0x06,
- 0x03,0x55,0x04,0x03,0x13,0x04,0x74,0x65,0x73,0x74,0x18,0x0f,0x32,0x30,0x32,0x32,
- 0x31,0x31,0x32,0x32,0x30,0x39,0x31,0x36,0x34,0x37,0x5a,0x30,0x64,0x30,0x62,0x30,
- 0x3a,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14,0xbd,0x25,
- 0xa0,0xdf,0xc3,0x21,0xf2,0xd8,0xed,0x19,0x63,0x0a,0x4b,0x90,0x6d,0xc3,0x0f,0xe7,
- 0x79,0x20,0x04,0x14,0xe2,0x6d,0x1e,0xdf,0x83,0x8e,0xa2,0x1f,0xc3,0x00,0xdd,0x44,
- 0x6f,0x8a,0x4d,0x70,0x0c,0x02,0xe3,0x1f,0x02,0x01,0x7f,0x80,0x00,0x18,0x0f,0x32,
- 0x30,0x32,0x32,0x31,0x31,0x32,0x32,0x30,0x39,0x31,0x36,0x34,0x37,0x5a,0xa0,0x11,
- 0x18,0x0f,0x32,0x30,0x32,0x32,0x31,0x31,0x32,0x32,0x31,0x39,0x31,0x36,0x34,0x37,
- 0x5a,0xa1,0x23,0x30,0x21,0x30,0x1f,0x06,0x09,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,
- 0x01,0x02,0x04,0x12,0x04,0x10,0x86,0x45,0x82,0x11,0xe6,0x62,0x43,0x83,0xbc,0x01,
- 0xe4,0x5c,0x48,0x87,0xcd,0x2e,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
- 0x01,0x01,0x0b,0x05,0x00,0x03,0x81,0x81,0x00,0x42,0x32,0xa9,0x24,0x97,0x8c,0xc5,
- 0x35,0x37,0xe7,0x14,0xf0,0x84,0x7e,0x69,0xf1,0x99,0xf8,0xf0,0x02,0x7d,0xe4,0xd8,
- 0x25,0x78,0x65,0x86,0x40,0xf6,0x30,0xc1,0x50,0x57,0x16,0x13,0xe9,0xe5,0xbc,0xa9,
- 0xbb,0x87,0xce,0xb8,0x0d,0x35,0x5d,0xad,0x68,0x3b,0x34,0x9f,0x82,0x2b,0xe5,0x1f,
- 0xcc,0xd5,0x54,0x8a,0xe3,0xd7,0xed,0xc9,0x7d,0xb6,0x50,0xd2,0xcb,0xc2,0xff,0x03,
- 0x24,0x8c,0xcf,0x49,0x40,0xd4,0x7f,0xcb,0xc0,0x20,0x75,0x78,0x45,0xb8,0x50,0x3c,
- 0x84,0xdd,0xdc,0xb7,0xfc,0xcd,0x64,0xc3,0x81,0xc6,0xb6,0xcd,0xc5,0xe9,0xc4,0x70,
- 0x31,0x30,0x7c,0xff,0x93,0xc3,0x9d,0x55,0x7b,0x32,0x77,0x53,0x07,0x45,0xc2,0x80,
- 0x7b,0x9b,0xfb,0x0e,0x45,0x27,0xf2,0xc5,0x16),
- chunk_from_chars(
- 0x30,0x82,0x01,0x9c,0x0a,0x01,0x00,0xa0,0x82,0x01,0x95,0x30,0x82,0x01,0x91,0x06,
- 0x09,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x01,0x04,0x82,0x01,0x82,0x30,0x82,
- 0x01,0x7e,0x30,0x81,0xe8,0xa1,0x33,0x30,0x31,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,
- 0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0a,0x13,
- 0x0a,0x73,0x74,0x72,0x6f,0x6e,0x67,0x53,0x77,0x61,0x6e,0x31,0x0d,0x30,0x0b,0x06,
- 0x03,0x55,0x04,0x03,0x13,0x04,0x74,0x65,0x73,0x74,0x18,0x0f,0x32,0x30,0x32,0x32,
- 0x31,0x31,0x32,0x32,0x30,0x39,0x32,0x32,0x32,0x34,0x5a,0x30,0x7b,0x30,0x79,0x30,
- 0x3b,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14,0xbd,0x25,
- 0xa0,0xdf,0xc3,0x21,0xf2,0xd8,0xed,0x19,0x63,0x0a,0x4b,0x90,0x6d,0xc3,0x0f,0xe7,
- 0x79,0x20,0x04,0x14,0xe2,0x6d,0x1e,0xdf,0x83,0x8e,0xa2,0x1f,0xc3,0x00,0xdd,0x44,
- 0x6f,0x8a,0x4d,0x70,0x0c,0x02,0xe3,0x1f,0x02,0x02,0x00,0x80,0xa1,0x16,0x18,0x0f,
- 0x32,0x30,0x32,0x32,0x31,0x31,0x31,0x35,0x31,0x38,0x34,0x30,0x35,0x34,0x5a,0xa0,
- 0x03,0x0a,0x01,0x01,0x18,0x0f,0x32,0x30,0x32,0x32,0x31,0x31,0x32,0x32,0x30,0x39,
- 0x32,0x32,0x32,0x34,0x5a,0xa0,0x11,0x18,0x0f,0x32,0x30,0x32,0x32,0x31,0x31,0x32,
- 0x32,0x31,0x39,0x32,0x32,0x32,0x34,0x5a,0xa1,0x23,0x30,0x21,0x30,0x1f,0x06,0x09,
- 0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x02,0x04,0x12,0x04,0x10,0xf2,0x47,0xbd,
- 0xd2,0xdd,0x6d,0x58,0xba,0xa4,0x6f,0xa5,0xed,0x31,0xb1,0x37,0x89,0x30,0x0d,0x06,
- 0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x03,0x81,0x81,0x00,
- 0x17,0x96,0x3b,0x5a,0x4d,0x4e,0x90,0x8a,0xdf,0xe9,0x2b,0x1c,0x48,0x15,0x5d,0x8e,
- 0xed,0xf0,0xa6,0x42,0x3a,0x9c,0x71,0xd9,0x6a,0xa6,0xc1,0xfd,0xef,0xe8,0x0a,0xa1,
- 0x61,0x46,0xe4,0x04,0x5c,0x64,0xaf,0x47,0x95,0xdd,0x4c,0xba,0x8e,0x53,0xf6,0x9b,
- 0xbc,0x16,0xcb,0xeb,0xfe,0x80,0x6a,0x70,0x54,0x10,0x59,0x40,0x5b,0xa0,0x2b,0xb3,
- 0x62,0x27,0x9e,0x5d,0xd2,0xd6,0x15,0x2a,0x9d,0xa3,0xb1,0xcb,0x44,0x09,0xd8,0x29,
- 0xb5,0x55,0xd9,0x63,0x86,0xd5,0xb3,0x3c,0x4b,0x78,0x14,0x5a,0x27,0x37,0x3a,0x28,
- 0xd8,0xae,0x69,0x51,0x2e,0x7d,0xf1,0x06,0xc1,0xac,0x4e,0x5d,0x25,0x7a,0xd2,0xf4,
- 0x41,0xfd,0x9f,0xbf,0x05,0xc1,0x70,0xa5,0x3f,0x7a,0x53,0x06,0x85,0x7b,0xeb,0x94)
-};
START_TEST(test_gen_serial_numbers)
{
chunk_t encoding, serial, serial_asn1;
- certificate_t *cert, *crl, *ocsp_req, *acert, *acert1;
- enumerator_t *enumerator;
+ certificate_t *cert, *crl, *ocsp_req, *ocsp_rsp, *acert, *acert1;
+ time_t revocation_time, this_update, next_update;
+ ocsp_request_t *ocsp_request;
+ ocsp_response_t *ocsp_resp;
+ cert_validation_t status;
+ crl_reason_t revocation_reason;
crl_t *x509_crl;
x509_t *x509;
ac_t *ac;
size_t offset;
u_char *pos;
+ enumerator_t *enumerator;
/**
* Use serial number with canonical encoding (no leading zeroes)
pos = encoding.ptr + 68;
serial_asn1 = chunk_create(pos, 1 + *pos);
ck_assert_chunk_eq(serial_asn1, serial_numbers[_i].serial_asn1);
+ ocsp_req->destroy(ocsp_req);
+
+ /* parse ocsp request */
+ ocsp_req = parse_ocsp_request(encoding);
+ ocsp_request = (ocsp_request_t*)ocsp_req;
+
+ /* test ocsp request */
+ enumerator = ocsp_request->create_request_enumerator(ocsp_request);
+ ck_assert(enumerator->enumerate(enumerator, NULL, NULL, NULL, &serial));
+ ck_assert_chunk_eq(serial, serial_numbers[_i].serial);
+ enumerator->destroy(enumerator);
chunk_free(&encoding);
+ /* create ocsp response */
+ status = (_i % 2) ? VALIDATION_GOOD : VALIDATION_REVOKED;
+ ocsp_rsp = create_ocsp_response(ocsp_request, status, cert);
+
+ /* the ASN.1 TLV (Type-Length-Value) encoding of an OCSP response is
+ *
+ * 0 "OCSPResponse", ASN1_SEQUENCE
+ * 1 "responseStatus", ASN1_ENUMERATED
+ * 1 "responseBytesContext", ASN1_CONTEXT_C_0
+ * 2 "responseBytes", ASN1_SEQUENCE
+ * 3 "responseType", ASN1_OID
+ * 3 "response", ASN1_OCTET_STRING
+ * 4 "BasicOCSPResponse", ASN1_SEQUENCE
+ * 5 "tbsResponseData", ASN1_SEQUENCE
+ * 6 "responderIdContext", ASN1_CONTEXT_C_1
+ * 6 "producedAt", ASN1_GENERALIZEDTIME
+ * 6 "responses", ASN1_SEQUENCE
+ * 7 "singleResponse", ASN1_SEQUENCE
+ * 8 "certID", ASN1_SEQUENCE
+ * 9 "algorithm", ASN1_SEQUENCE
+ * 9 "issuerNameHash", ASN1_OCTET_STRING
+ * 9 "issuerKeyHash", ASN1_OCTET_STRING
+ * 9 "serialNumber", ASN1_INTEGER
+ *
+ * The one octet length field of the serialNumber (8) is at
+ * pos = 4 (TL0) + 3 (TLV1) + 4 (TL1) + 4 (TL2) + 11 (TLV3) + 4 (TL3) +
+ 4 (TL4) + 3 (TL5) + 53 (TLV6) + 17 (TVL6) + 2 (TL6) + 2 (TL7) +
+ 2 (TL8) + 11 (TLV9) + 22 (TLV9) + 22 (TLV9) + 1 (T9) = 169
+ */
+ ck_assert(ocsp_rsp->get_encoding(ocsp_rsp, CERT_ASN1_DER, &encoding));
+ DBG2(DBG_LIB, "ocsp response: %B", &encoding);
+
+ /* check ASN.1 integer encoding of requested serial number */
+ pos = encoding.ptr + 169;
+ serial_asn1 = chunk_create(pos, 1 + *pos);
+ ck_assert_chunk_eq(serial_asn1, serial_numbers[_i].serial_asn1);
+ ocsp_rsp->destroy(ocsp_rsp);
+
+ /* parse ocsp response */
+ ocsp_rsp = parse_ocsp_response(encoding);
+ ocsp_resp = (ocsp_response_t*)ocsp_rsp;
+
/* test ocsp response */
- if (_i == 2 || _i == 3)
+ ck_assert_chunk_eq(ocsp_request->get_nonce(ocsp_request),
+ ocsp_resp->get_nonce(ocsp_resp));
+
+ status = ocsp_resp->get_status(ocsp_resp, x509, x509, &revocation_time,
+ &revocation_reason, &this_update, &next_update);
+ if (_i % 2)
{
- certificate_t *ocsp_rsp;
- ocsp_response_t *ocsp_resp;
- cert_validation_t status;
- crl_reason_t revocation_reason;
- time_t revocation_time, this_update, next_update;
- enumerator_t *enumerator;
-
- ocsp_rsp = parse_ocsp_response(ocsp_responses[_i-2]);
- ocsp_resp = (ocsp_response_t*)ocsp_rsp;
-
- status = ocsp_resp->get_status(ocsp_resp, x509, x509, &revocation_time,
- &revocation_reason, &this_update, &next_update);
- if (_i == 2)
- {
- ck_assert(status == VALIDATION_GOOD);
- }
- else
- {
- ck_assert(status == VALIDATION_REVOKED);
- ck_assert(revocation_reason == CRL_REASON_KEY_COMPROMISE);
- }
-
- enumerator = ocsp_resp->create_response_enumerator(ocsp_resp);
- ck_assert(enumerator->enumerate(enumerator, &serial, &status,
- &revocation_time, &revocation_reason));
- ck_assert_chunk_eq(serial, serial_numbers[_i].serial);
- if (_i == 2)
- {
- ck_assert(status == VALIDATION_GOOD);
- }
- else
- {
- ck_assert(status == VALIDATION_REVOKED);
- ck_assert(revocation_reason == CRL_REASON_KEY_COMPROMISE);
- }
- enumerator->destroy(enumerator);
-
- ocsp_rsp->destroy(ocsp_rsp);
+ ck_assert(status == VALIDATION_GOOD);
+ }
+ else
+ {
+ ck_assert(status == VALIDATION_REVOKED);
+ ck_assert(revocation_reason == CRL_REASON_KEY_COMPROMISE);
}
+ enumerator = ocsp_resp->create_response_enumerator(ocsp_resp);
+ ck_assert(enumerator->enumerate(enumerator, &serial, &status,
+ &revocation_time, &revocation_reason));
+ ck_assert_chunk_eq(serial, serial_numbers[_i].serial);
+ if (_i % 2)
+ {
+ ck_assert(status == VALIDATION_GOOD);
+ }
+ else
+ {
+ ck_assert(status == VALIDATION_REVOKED);
+ ck_assert(revocation_reason == CRL_REASON_KEY_COMPROMISE);
+ }
+ enumerator->destroy(enumerator);
+ chunk_free(&encoding);
+
/* create attribute certificate */
acert = create_acert(serial_numbers[_i].serial, cert);
cert->destroy(cert);
crl->destroy(crl);
ocsp_req->destroy(ocsp_req);
+ ocsp_rsp->destroy(ocsp_rsp);
acert->destroy(acert);
acert1->destroy(acert1);