2 * Copyright (C) 2008-2009 Martin Willi
3 * Copyright (C) 2007 Andreas Steffen
4 * Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "x509_ocsp_request.h"
22 #include <asn1/asn1.h>
23 #include <utils/identification.h>
24 #include <utils/linked_list.h>
26 #include <credentials/certificates/x509.h>
27 #include <credentials/keys/private_key.h>
31 typedef struct private_x509_ocsp_request_t private_x509_ocsp_request_t
;
34 * private data of x509_ocsp_request
36 struct private_x509_ocsp_request_t
{
41 x509_ocsp_request_t
public;
44 * CA the candidates belong to
49 * Requestor name, subject of cert used if not set
51 identification_t
*requestor
;
54 * Requestor certificate, included in request
59 * Requestor private key to sign request
64 * list of certificates to check, x509_t
66 linked_list_t
*candidates
;
69 * nonce used in request
74 * encoded OCSP request
84 static const chunk_t ASN1_nonce_oid
= chunk_from_chars(
87 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
89 static const chunk_t ASN1_response_oid
= chunk_from_chars(
92 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
94 static const chunk_t ASN1_response_content
= chunk_from_chars(
99 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
103 * build requestorName
105 static chunk_t
build_requestorName(private_x509_ocsp_request_t
*this)
107 if (this->requestor
|| this->cert
)
108 { /* use requestor name, fallback to his cert subject */
109 if (!this->requestor
)
111 this->requestor
= this->cert
->get_subject(this->cert
);
112 this->requestor
= this->requestor
->clone(this->requestor
);
114 return asn1_wrap(ASN1_CONTEXT_C_1
, "m",
115 asn1_simple_object(ASN1_CONTEXT_C_4
,
116 this->requestor
->get_encoding(this->requestor
)));
123 * build Request, not using singleRequestExtensions
125 static chunk_t
build_Request(private_x509_ocsp_request_t
*this,
126 chunk_t issuerNameHash
, chunk_t issuerKeyHash
,
127 chunk_t serialNumber
)
129 return asn1_wrap(ASN1_SEQUENCE
, "m",
130 asn1_wrap(ASN1_SEQUENCE
, "mmmm",
131 asn1_algorithmIdentifier(OID_SHA1
),
132 asn1_simple_object(ASN1_OCTET_STRING
, issuerNameHash
),
133 asn1_simple_object(ASN1_OCTET_STRING
, issuerKeyHash
),
134 asn1_simple_object(ASN1_INTEGER
, serialNumber
)));
140 static chunk_t
build_requestList(private_x509_ocsp_request_t
*this)
142 chunk_t issuerNameHash
, issuerKeyHash
;
143 identification_t
*issuer
;
146 chunk_t list
= chunk_empty
;
147 public_key_t
*public;
149 cert
= (certificate_t
*)this->ca
;
150 public = cert
->get_public_key(cert
);
153 hasher_t
*hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
156 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1
,
159 enumerator_t
*enumerator
;
161 issuer
= cert
->get_subject(cert
);
162 if (hasher
->allocate_hash(hasher
, issuer
->get_encoding(issuer
),
165 enumerator
= this->candidates
->create_enumerator(
167 while (enumerator
->enumerate(enumerator
, &x509
))
169 chunk_t request
, serialNumber
;
171 serialNumber
= x509
->get_serial(x509
);
172 request
= build_Request(this, issuerNameHash
,
173 issuerKeyHash
, serialNumber
);
174 list
= chunk_cat("mm", list
, request
);
176 enumerator
->destroy(enumerator
);
177 chunk_free(&issuerNameHash
);
179 hasher
->destroy(hasher
);
184 DBG1(DBG_LIB
, "creating OCSP request failed, SHA1 not supported");
186 public->destroy(public);
190 DBG1(DBG_LIB
, "creating OCSP request failed, CA certificate has "
193 return asn1_wrap(ASN1_SEQUENCE
, "m", list
);
197 * build nonce extension
199 static chunk_t
build_nonce(private_x509_ocsp_request_t
*this)
203 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
204 if (!rng
|| !rng
->allocate_bytes(rng
, NONCE_LEN
, &this->nonce
))
206 DBG1(DBG_LIB
, "creating OCSP request nonce failed, no RNG found");
211 return asn1_wrap(ASN1_SEQUENCE
, "cm", ASN1_nonce_oid
,
212 asn1_simple_object(ASN1_OCTET_STRING
, this->nonce
));
216 * build acceptableResponses extension
218 static chunk_t
build_acceptableResponses(private_x509_ocsp_request_t
*this)
220 return asn1_wrap(ASN1_SEQUENCE
, "cc",
222 ASN1_response_content
);
226 * build requestExtensions
228 static chunk_t
build_requestExtensions(private_x509_ocsp_request_t
*this)
230 return asn1_wrap(ASN1_CONTEXT_C_2
, "m",
231 asn1_wrap(ASN1_SEQUENCE
, "mm",
233 build_acceptableResponses(this)));
239 static chunk_t
build_tbsRequest(private_x509_ocsp_request_t
*this)
241 return asn1_wrap(ASN1_SEQUENCE
, "mmm",
242 build_requestorName(this),
243 build_requestList(this),
244 build_requestExtensions(this));
248 * Build the optionalSignature
250 static chunk_t
build_optionalSignature(private_x509_ocsp_request_t
*this,
254 signature_scheme_t scheme
;
255 chunk_t certs
, signature
, encoding
;
257 switch (this->key
->get_type(this->key
))
259 /* TODO: use a generic mapping function */
261 oid
= OID_SHA1_WITH_RSA
;
262 scheme
= SIGN_RSA_EMSA_PKCS1_SHA1
;
265 oid
= OID_ECDSA_WITH_SHA1
;
266 scheme
= SIGN_ECDSA_WITH_SHA1_DER
;
269 DBG1(DBG_LIB
, "unable to sign OCSP request, %N signature not "
270 "supported", key_type_names
, this->key
->get_type(this->key
));
274 if (!this->key
->sign(this->key
, scheme
, tbsRequest
, &signature
))
276 DBG1(DBG_LIB
, "creating OCSP signature failed, skipped");
280 this->cert
->get_encoding(this->cert
, CERT_ASN1_DER
, &encoding
))
282 certs
= asn1_wrap(ASN1_CONTEXT_C_0
, "m",
283 asn1_wrap(ASN1_SEQUENCE
, "m", encoding
));
285 return asn1_wrap(ASN1_CONTEXT_C_0
, "m",
286 asn1_wrap(ASN1_SEQUENCE
, "cmm",
287 asn1_algorithmIdentifier(oid
),
288 asn1_bitstring("m", signature
),
293 * Build the OCSPRequest data
296 static chunk_t
build_OCSPRequest(private_x509_ocsp_request_t
*this)
298 chunk_t tbsRequest
, optionalSignature
= chunk_empty
;
300 tbsRequest
= build_tbsRequest(this);
303 optionalSignature
= build_optionalSignature(this, tbsRequest
);
305 return asn1_wrap(ASN1_SEQUENCE
, "mm", tbsRequest
, optionalSignature
);
309 METHOD(certificate_t
, get_type
, certificate_type_t
,
310 private_x509_ocsp_request_t
*this)
312 return CERT_X509_OCSP_REQUEST
;
315 METHOD(certificate_t
, get_subject
, identification_t
*,
316 private_x509_ocsp_request_t
*this)
318 certificate_t
*ca
= (certificate_t
*)this->ca
;
322 return this->requestor
;
326 return this->cert
->get_subject(this->cert
);
328 return ca
->get_subject(ca
);
331 METHOD(certificate_t
, get_issuer
, identification_t
*,
332 private_x509_ocsp_request_t
*this)
334 certificate_t
*ca
= (certificate_t
*)this->ca
;
336 return ca
->get_subject(ca
);
339 METHOD(certificate_t
, has_subject
, id_match_t
,
340 private_x509_ocsp_request_t
*this, identification_t
*subject
)
342 certificate_t
*current
;
343 enumerator_t
*enumerator
;
344 id_match_t match
, best
= ID_MATCH_NONE
;
346 enumerator
= this->candidates
->create_enumerator(this->candidates
);
347 while (enumerator
->enumerate(enumerator
, ¤t
))
349 match
= current
->has_subject(current
, subject
);
355 enumerator
->destroy(enumerator
);
359 METHOD(certificate_t
, has_issuer
, id_match_t
,
360 private_x509_ocsp_request_t
*this,
361 identification_t
*issuer
)
363 certificate_t
*ca
= (certificate_t
*)this->ca
;
365 return ca
->has_subject(ca
, issuer
);
368 METHOD(certificate_t
, issued_by
, bool,
369 private_x509_ocsp_request_t
*this, certificate_t
*issuer
,
370 signature_scheme_t
*scheme
)
372 DBG1(DBG_LIB
, "OCSP request validation not implemented!");
376 METHOD(certificate_t
, get_public_key
, public_key_t
*,
377 private_x509_ocsp_request_t
*this)
382 METHOD(certificate_t
, get_validity
, bool,
383 private_x509_ocsp_request_t
*this, time_t *when
, time_t *not_before
,
394 cert
= (certificate_t
*)this->ca
;
396 return cert
->get_validity(cert
, when
, not_before
, not_after
);
399 METHOD(certificate_t
, get_encoding
, bool,
400 private_x509_ocsp_request_t
*this, cred_encoding_type_t type
,
403 if (type
== CERT_ASN1_DER
)
405 *encoding
= chunk_clone(this->encoding
);
408 return lib
->encoding
->encode(lib
->encoding
, type
, NULL
, encoding
,
409 CRED_PART_X509_OCSP_REQ_ASN1_DER
, this->encoding
, CRED_PART_END
);
412 METHOD(certificate_t
, equals
, bool,
413 private_x509_ocsp_request_t
*this, certificate_t
*other
)
418 if (this == (private_x509_ocsp_request_t
*)other
)
422 if (other
->get_type(other
) != CERT_X509_OCSP_REQUEST
)
426 if (other
->equals
== (void*)equals
)
427 { /* skip allocation if we have the same implementation */
428 return chunk_equals(this->encoding
, ((private_x509_ocsp_request_t
*)other
)->encoding
);
430 if (!other
->get_encoding(other
, CERT_ASN1_DER
, &encoding
))
434 equal
= chunk_equals(this->encoding
, encoding
);
439 METHOD(certificate_t
, get_ref
, certificate_t
*,
440 private_x509_ocsp_request_t
*this)
443 return &this->public.interface
.interface
;
446 METHOD(certificate_t
, destroy
, void,
447 private_x509_ocsp_request_t
*this)
449 if (ref_put(&this->ref
))
451 DESTROY_IF((certificate_t
*)this->ca
);
452 DESTROY_IF(this->requestor
);
453 DESTROY_IF(this->cert
);
454 DESTROY_IF(this->key
);
455 this->candidates
->destroy_offset(this->candidates
, offsetof(certificate_t
, destroy
));
456 chunk_free(&this->nonce
);
457 chunk_free(&this->encoding
);
463 * create an empty but initialized OCSP request
465 static private_x509_ocsp_request_t
*create_empty()
467 private_x509_ocsp_request_t
*this;
473 .get_type
= _get_type
,
474 .get_subject
= _get_subject
,
475 .get_issuer
= _get_issuer
,
476 .has_subject
= _has_subject
,
477 .has_issuer
= _has_issuer
,
478 .issued_by
= _issued_by
,
479 .get_public_key
= _get_public_key
,
480 .get_validity
= _get_validity
,
481 .get_encoding
= _get_encoding
,
488 .candidates
= linked_list_create(),
498 x509_ocsp_request_t
*x509_ocsp_request_gen(certificate_type_t type
, va_list args
)
500 private_x509_ocsp_request_t
*req
;
502 private_key_t
*private;
503 identification_t
*subject
;
505 req
= create_empty();
508 switch (va_arg(args
, builder_part_t
))
511 cert
= va_arg(args
, certificate_t
*);
512 if (cert
->get_type(cert
) == CERT_X509
)
514 req
->ca
= (x509_t
*)cert
->get_ref(cert
);
518 cert
= va_arg(args
, certificate_t
*);
519 if (cert
->get_type(cert
) == CERT_X509
)
521 req
->candidates
->insert_last(req
->candidates
,
522 cert
->get_ref(cert
));
525 case BUILD_SIGNING_CERT
:
526 cert
= va_arg(args
, certificate_t
*);
527 req
->cert
= cert
->get_ref(cert
);
529 case BUILD_SIGNING_KEY
:
530 private = va_arg(args
, private_key_t
*);
531 req
->key
= private->get_ref(private);
534 subject
= va_arg(args
, identification_t
*);
535 req
->requestor
= subject
->clone(subject
);
547 req
->encoding
= build_OCSPRequest(req
);