ocsp_resp_validate.c
Go to the documentation of this file.
1 /**
2  * @file ocsp_resp_validate.c
3  * @brief OCSP response validation
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL OCSP_TRACE_LEVEL
33 
34 //Dependencies
36 #include "pkix/x509_cert_parse.h"
38 #include "pkix/x509_sign_verify.h"
39 #include "encoding/asn1.h"
40 #include "encoding/oid.h"
41 #include "debug.h"
42 
43 //Check crypto library configuration
44 #if (OCSP_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief OCSP response validation
49  * @param[in] response Pointer to the OCSP response to be verified
50  * @param[in] certInfo End entity certificate
51  * @param[in] issuerCertInfo Issuer's certificate
52  * @param[in] nonce Pointer to the random nonce (optional parameter)
53  * @param[in] nonceLen Length of the nonce, in bytes (optional parameter)
54  * @return Error code
55  **/
56 
58  const X509CertInfo *certInfo, const X509CertInfo *issuerCertInfo,
59  const uint8_t *nonce, size_t nonceLen)
60 {
61  error_t error;
62  const OcspBasicResponse *basicResponse;
63  const OcspSingleResponse *singleResponse;
64 
65  //Check parameters
66  if(response == NULL || certInfo == NULL || issuerCertInfo == NULL)
68 
69  //In case of errors, the OCSP responder may return an error message. These
70  //messages are not signed (refer to RFC 6960, section 2.3)
73 
74  //OCSP responders shall be capable of producing responses of the
75  //id-pkix-ocsp-basic response type
76  if(oidComp(response->responseType.value, response->responseType.length,
78  {
80  }
81 
82  //Point to the basic response
83  basicResponse = &response->basicResponse;
84 
85  //The response must include a SingleResponse for each certificate in
86  //the request
87  if(basicResponse->tbsResponseData.numResponses < 1)
89 
90  //Point to the response
91  singleResponse = &basicResponse->tbsResponseData.responses[0];
92 
93  //The OCSP client must confirm that the certificate identified in a received
94  //response corresponds to the certificate that was identified in the
95  //corresponding request
96  error = ocspCheckCertId(&singleResponse->certId, certInfo, issuerCertInfo);
97  //Any error to report?
98  if(error)
99  return error;
100 
101  //The OCSP client must confirm that the signature on the response is valid
102  error = ocspCheckResponseSignature(basicResponse, issuerCertInfo);
103  //Any error to report?
104  if(error)
105  return error;
106 
107  //Check the validity interval of the OCSP response
108  error = ocspCheckValidity(singleResponse);
109  //Any error to report?
110  if(error)
111  return error;
112 
113  //The Nonce extension is used to cryptographically binds a request and a
114  //response to prevent replay attacks (refer to RFC 8954, section 2.1)
115  error = ocspCheckNonce(&basicResponse->tbsResponseData.responseExtensions,
116  nonce, nonceLen);
117 
118  //Return status code
119  return error;
120 }
121 
122 
123 /**
124  * @brief Verify response signature
125  * @param[in] basicResponse Pointer to the basic response
126  * @param[in] issuerCertInfo Issuer's certificate
127  * @return Error code
128  **/
129 
131  const X509CertInfo *issuerCertInfo)
132 {
133  error_t error;
134  const OcspResponderId *responderId;
135 
136  //Point to the ResponderID information
137  responderId = &basicResponse->tbsResponseData.responderId;
138 
139  //Check the identity of the signer
140  error = ocspCheckResponderId(responderId, issuerCertInfo);
141 
142  //A certificate's issuer can either sign the OCSP responses itself or
143  //explicitly designate this authority to another entity
144  if(!error)
145  {
146  //The value for signature shall be computed on the hash of the DER
147  //encoding of ResponseData
148  error = x509VerifySignature(&basicResponse->tbsResponseData.raw,
149  &basicResponse->signatureAlgo,
150  &issuerCertInfo->tbsCert.subjectPublicKeyInfo,
151  &basicResponse->signature);
152  }
153 #if (OCSP_SIGN_DELEGATION_SUPPORT == ENABLED)
154  else
155  {
156  size_t length;
157  const uint8_t *data;
158  Asn1Tag tag;
159  X509CertInfo *responderCertInfo;
160 
161  //Allocate a memory buffer to store X.509 certificate info
162  responderCertInfo = cryptoAllocMem(sizeof(X509CertInfo));
163 
164  //Successful memory allocation?
165  if(responderCertInfo != NULL)
166  {
167  //The responder may include certificates in the Certs field of
168  //BasicOCSPResponse that help the OCSP client verify the responder's
169  //signature (refer to RFC 6960, section 4.2.2.3)
170  data = basicResponse->certs.raw.value;
171  length = basicResponse->certs.raw.length;
172 
173  //Loop through the list of certificates
174  while(length > 0)
175  {
176  //Determine the length of the X.509 certificate
177  error = asn1ReadTag(data, length, &tag);
178 
179  //Check status code
180  if(!error)
181  {
182  //Parse X.509 certificate
184  responderCertInfo);
185 
186  //Check status code
187  if(!error)
188  {
189  //This certificate must be issued directly to the responder by
190  //the cognizant CA (refer to RFC 6960, section 2.6)
191  error = ocspCheckResponderCert(responderId, responderCertInfo,
192  issuerCertInfo);
193  }
194 
195  //Check status code
196  if(!error)
197  {
198  //The value for signature shall be computed on the hash of the
199  //DER encoding of ResponseData
200  error = x509VerifySignature(&basicResponse->tbsResponseData.raw,
201  &basicResponse->signatureAlgo,
202  &responderCertInfo->tbsCert.subjectPublicKeyInfo,
203  &basicResponse->signature);
204  }
205 
206  //Check status code
207  if(!error)
208  {
209  //The signature on the response is valid
210  break;
211  }
212 
213  //Point to the next certificate
214  data += tag.totalLength;
215  length -= tag.totalLength;
216  }
217  else
218  {
219  //The Certs field is malformed
220  break;
221  }
222  }
223 
224  //Release previously allocated memory
225  cryptoFreeMem(responderCertInfo);
226  }
227  else
228  {
229  //Failed to allocate memory
230  error = ERROR_OUT_OF_MEMORY;
231  }
232  }
233 #endif
234 
235  //Return status code
236  return error;
237 }
238 
239 
240 /**
241  * @brief Check responder's certificate
242  * @param[in] responderId Pointer to the responder identifier
243  * @param[in] responderCertInfo Responder's certificate
244  * @param[in] issuerCertInfo Issuer's certificate
245  * @return Error code
246  **/
247 
249  const X509CertInfo *responderCertInfo, const X509CertInfo *issuerCertInfo)
250 {
251  error_t error;
252  const X509Extensions *extensions;
253 
254  //Point to the list of extensions
255  extensions = &responderCertInfo->tbsCert.extensions;
256 
257  //The ResponderID information must correspond to the certificate that was
258  //used to sign the response (refer to RFC 6960, section 4.2.2.3)
259  error = ocspCheckResponderId(responderId, responderCertInfo);
260  //Any error to report?
261  if(error)
262  return error;
263 
264  //The OCSP signing certificate must contain an extension of type
265  //id-pkix-ocsp-nocheck (refer to BR, section 4.9.9)
266  if(!extensions->pkixOcspNoCheck.present)
267  return ERROR_BAD_CERTIFICATE;
268 
269  //OCSP signing delegation shall be designated by the inclusion of
270  //id-kp-OCSPSigning in an extended key usage certificate extension included
271  //in the OCSP response signer's certificate
272  if((extensions->extKeyUsage.bitmap & X509_EXT_KEY_USAGE_OCSP_SIGNING) == 0)
273  return ERROR_BAD_CERTIFICATE;
274 
275  //The certificate must be issued directly by the CA that is identified in
276  //the request (refer to RFC 6960, section 4.2.2.2)
277  error = x509ValidateCertificate(responderCertInfo, issuerCertInfo, 0);
278 
279  //Return status code
280  return error;
281 }
282 
283 
284 /**
285  * @brief Check responder identifier
286  * @param[in] responderId Pointer to the responder identifier
287  * @param[in] issuerCertInfo Issuer's certificate
288  * @return Error code
289  **/
290 
292  const X509CertInfo *issuerCertInfo)
293 {
294  error_t error;
295  const X509SubjectPublicKeyInfo *responderPublicKeyInfo;
296  uint8_t digest[SHA1_DIGEST_SIZE];
297 
298  //Initialize status code
299  error = NO_ERROR;
300 
301  //The responder ID can be either the name of the responder or a hash of
302  //the responder's public key
303  if(responderId->keyHash.value != NULL &&
304  responderId->keyHash.length > 0)
305  {
306  //Point to the responder's public key
307  responderPublicKeyInfo = &issuerCertInfo->tbsCert.subjectPublicKeyInfo;
308 
309  //Compute the SHA-1 hash of responder's public key
310  error = sha1Compute(responderPublicKeyInfo->rawSubjectPublicKey.value,
311  responderPublicKeyInfo->rawSubjectPublicKey.length, digest);
312 
313  //Check status code
314  if(!error)
315  {
316  //The identity of the signer must match the intended recipient of
317  //the request
318  if(responderId->keyHash.length != SHA1_DIGEST_SIZE ||
319  osMemcmp(responderId->keyHash.value, digest, SHA1_DIGEST_SIZE) != 0)
320  {
321  error = ERROR_WRONG_ISSUER;
322  }
323  }
324  }
325  else if(responderId->name.raw.value != NULL &&
326  responderId->name.raw.length > 0)
327  {
328  //The identity of the signer must match the intended recipient of the
329  //request
330  if(!x509CompareName(responderId->name.raw.value,
331  responderId->name.raw.length,
332  issuerCertInfo->tbsCert.subject.raw.value,
333  issuerCertInfo->tbsCert.subject.raw.length))
334  {
335  error = ERROR_WRONG_ISSUER;
336  }
337  }
338  else
339  {
340  //The responder ID is not valid
341  error = ERROR_WRONG_ISSUER;
342  }
343 
344  //Return status code
345  return error;
346 }
347 
348 
349 /**
350  * @brief Check certificate identifier
351  * @param[in] certId Pointer to the certificate identifier
352  * @param[in] certInfo End entity certificate
353  * @param[in] issuerCertInfo Issuer's certificate
354  * @return Error code
355  **/
356 
357 error_t ocspCheckCertId(const OcspCertId *certId, const X509CertInfo *certInfo,
358  const X509CertInfo *issuerCertInfo)
359 {
360  error_t error;
361  const HashAlgo *hashAlgo;
362  const X509SubjectPublicKeyInfo *issuerPublicKeyInfo;
363  uint8_t digest[MAX_HASH_DIGEST_SIZE];
364 
365  //Retrieve the hash algorithm that was used to generate the IssuerNameHash
366  //and IssuerKeyHash values
367  hashAlgo = ocspGetHashAlgo(certId->hashAlgo.value, certId->hashAlgo.length);
368  //Invalid hash algorithm?
369  if(hashAlgo == NULL)
371 
372  //Compute the hash of the issuer's distinguished name (DN). The hash shall
373  //be calculated over the DER encoding of the issuer's name field in the
374  //certificate being checked (refer to RFC 6960, section 4.1.1)
375  error = hashAlgo->compute(certInfo->tbsCert.issuer.raw.value,
376  certInfo->tbsCert.issuer.raw.length, digest);
377  //Any error to report?
378  if(error)
379  return error;
380 
381  //Check IssuerNameHash value
382  if(certId->issuerNameHash.length != hashAlgo->digestSize ||
383  osMemcmp(certId->issuerNameHash.value, digest, hashAlgo->digestSize) != 0)
384  {
385  return ERROR_WRONG_IDENTIFIER;
386  }
387 
388  //Point to the issuer's public key
389  issuerPublicKeyInfo = &issuerCertInfo->tbsCert.subjectPublicKeyInfo;
390 
391  //Compute the hash of the issuer's public key. The hash shall be calculated
392  //over the value (excluding tag and length) of the subject public key field
393  //in the issuer's certificate
394  error = hashAlgo->compute(issuerPublicKeyInfo->rawSubjectPublicKey.value,
395  issuerPublicKeyInfo->rawSubjectPublicKey.length, digest);
396  //Any error to report?
397  if(error)
398  return error;
399 
400  //Check IssuerKeyHash value
401  if(certId->issuerKeyHash.length != hashAlgo->digestSize ||
402  osMemcmp(certId->issuerKeyHash.value, digest, hashAlgo->digestSize) != 0)
403  {
404  return ERROR_WRONG_IDENTIFIER;
405  }
406 
407  //Check serial number
408  if(certId->serialNumber.length != certInfo->tbsCert.serialNumber.length ||
410  certInfo->tbsCert.serialNumber.length) != 0)
411  {
412  return ERROR_WRONG_IDENTIFIER;
413  }
414 
415  //The certificate identified in the OCSP response corresponds to the
416  //certificate that was identified in the corresponding request
417  return NO_ERROR;
418 }
419 
420 
421 /**
422  * @brief Check the validity interval of the OCSP response
423  * @param[in] singleResponse Pointer to the OCSP response
424  * @return Error code
425  **/
426 
428 {
429  error_t error;
430  time_t currentTime;
431  DateTime currentDate;
432 
433  //Initialize status
434  error = NO_ERROR;
435 
436  //Retrieve current time
437  currentTime = getCurrentUnixTime();
438 
439  //Any real-time clock implemented?
440  if(currentTime != 0)
441  {
442  //Convert Unix timestamp to date
443  convertUnixTimeToDate(currentTime, &currentDate);
444 
445  //The time at which the status being indicated is known to be correct
446  //must be sufficiently recent
447  if(compareDateTime(&currentDate, &singleResponse->thisUpdate) < 0)
448  {
449  error = ERROR_RESPONSE_EXPIRED;
450  }
451 
452  //The NextUpdate field is optional
453  if(singleResponse->nextUpdate.year != 0)
454  {
455  //When available, the time at or before which newer information will
456  //be available about the status of the certificate must be greater
457  //than the current time
458  if(compareDateTime(&currentDate, &singleResponse->nextUpdate) > 0)
459  {
460  error = ERROR_RESPONSE_EXPIRED;
461  }
462  }
463  else
464  {
465  //If NextUpdate is not set, the responder is indicating that newer
466  //revocation information is available all the time
467  }
468  }
469 
470  //Return status code
471  return error;
472 }
473 
474 
475 /**
476  * @brief Check nonce
477  * @param[in] extensions Pointer to the OCSP extensions
478  * @param[in] nonce Pointer to the random nonce (optional parameter)
479  * @param[in] nonceLen Length of the nonce, in bytes (optional parameter)
480  * @return Error code
481  **/
482 
484  size_t nonceLen)
485 {
486  error_t error;
487 
488  //Initialize status code
489  error = NO_ERROR;
490 
491  //Check whether a Nonce extension was sent in the OCSP request
492  if(nonce != NULL && nonceLen > 0)
493  {
494  //Any Nonce extension received in the response?
495  if(extensions->nonce.value != NULL && extensions->nonce.length > 0)
496  {
497  //Ensure the received nonce matches the nonce sent in the request
498  if(extensions->nonce.length != nonceLen ||
499  osMemcmp(extensions->nonce.value, nonce, nonceLen) != 0)
500  {
501  return ERROR_WRONG_NONCE;
502  }
503  }
504  else
505  {
506  //The OCSP responder may choose not to send the Nonce extension in the
507  //OCSP response even if the client has sent the Nonce extension in the
508  //request (refer to RFC 8954, section 3.1)
509  error = ERROR_WRONG_NONCE;
510  }
511  }
512  else
513  {
514  //The OCSP request does not contain a Nonce extension
515  }
516 
517  //Return status code
518  return error;
519 }
520 
521 #endif
error_t ocspCheckResponderCert(const OcspResponderId *responderId, const X509CertInfo *responderCertInfo, const X509CertInfo *issuerCertInfo)
Check responder's certificate.
X.509 certificate parsing.
uint8_t extensions[]
Definition: ntp_common.h:207
error_t ocspCheckValidity(const OcspSingleResponse *singleResponse)
Check the validity interval of the OCSP response.
error_t ocspCheckCertId(const OcspCertId *certId, const X509CertInfo *certInfo, const X509CertInfo *issuerCertInfo)
Check certificate identifier.
error_t x509ValidateCertificate(const X509CertInfo *certInfo, const X509CertInfo *issuerCertInfo, uint_t pathLen)
X.509 certificate validation.
const uint8_t * value
Definition: x509_common.h:665
X509TbsCertificate tbsCert
Definition: x509_common.h:1072
@ ERROR_WRONG_ISSUER
Definition: error.h:304
X509Extensions extensions
Definition: x509_common.h:1062
OID (Object Identifier)
uint16_t year
Definition: date_time.h:48
error_t x509ParseCertificate(const uint8_t *data, size_t length, X509CertInfo *certInfo)
Parse a X.509 certificate.
uint8_t data[]
Definition: ethernet.h:222
size_t digestSize
Definition: crypto.h:1052
@ ERROR_RESPONSE_EXPIRED
Definition: error.h:305
X509OctetString raw
Definition: ocsp_common.h:250
OcspResponderId responderId
Definition: ocsp_common.h:252
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
void convertUnixTimeToDate(time_t t, DateTime *date)
Convert Unix timestamp to date.
Definition: date_time.c:198
X509OctetString issuerNameHash
Definition: ocsp_common.h:144
error_t asn1ReadTag(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an ASN.1 tag from the input stream.
Definition: asn1.c:52
OcspSingleResponse responses[OCSP_MAX_RESPONSES]
Definition: ocsp_common.h:255
X509OctetString serialNumber
Definition: ocsp_common.h:146
int_t oidComp(const uint8_t *oid1, size_t oidLen1, const uint8_t *oid2, size_t oidLen2)
Compare object identifiers.
Definition: oid.c:103
error_t x509VerifySignature(const X509OctetString *tbsData, const X509SignAlgoId *signAlgoId, const X509SubjectPublicKeyInfo *publicKeyInfo, const X509OctetString *signature)
Certificate signature verification.
BasicOCSPResponse structure.
Definition: ocsp_common.h:275
OcspTbsResponseData tbsResponseData
Definition: ocsp_common.h:276
bool_t x509CompareName(const uint8_t *name1, size_t nameLen1, const uint8_t *name2, size_t nameLen2)
Compare distinguished names.
error_t sha1Compute(const void *data, size_t length, uint8_t *digest)
Digest a message using SHA-1.
size_t totalLength
Definition: asn1.h:108
X509OctetString raw
Definition: ocsp_common.h:266
#define MAX_HASH_DIGEST_SIZE
@ ERROR_UNSUPPORTED_HASH_ALGO
Definition: error.h:130
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
X509OctetString issuerKeyHash
Definition: ocsp_common.h:145
X.509 certificate.
Definition: x509_common.h:1071
error_t
Error codes.
Definition: error.h:43
const HashAlgo * ocspGetHashAlgo(const uint8_t *oid, size_t length)
Get the hash algorithm that matches the specified identifier.
Definition: ocsp_common.c:85
HashAlgoCompute compute
Definition: crypto.h:1055
X509OctetString keyHash
Definition: ocsp_common.h:240
ASN.1 tag.
Definition: asn1.h:102
OcspBasicResponse basicResponse
Definition: ocsp_common.h:292
error_t ocspCheckNonce(const OcspExtensions *extensions, const uint8_t *nonce, size_t nonceLen)
Check nonce.
error_t ocspCheckResponderId(const OcspResponderId *responderId, const X509CertInfo *issuerCertInfo)
Check responder identifier.
X509SignAlgoId signatureAlgo
Definition: ocsp_common.h:277
@ ERROR_BAD_CERTIFICATE
Definition: error.h:235
X509SerialNumber serialNumber
Definition: x509_common.h:1056
X509OctetString hashAlgo
Definition: ocsp_common.h:143
@ ERROR_UNEXPECTED_RESPONSE
Definition: error.h:70
Date and time representation.
Definition: date_time.h:47
uint8_t length
Definition: tcp.h:368
X509OctetString responseType
Definition: ocsp_common.h:291
const uint8_t PKIX_OCSP_BASIC_OID[9]
Definition: ocsp_common.c:42
OCSP extensions.
Definition: ocsp_common.h:176
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
RSA/DSA/ECDSA/EdDSA signature verification.
error_t ocspValidateResponse(const OcspResponse *response, const X509CertInfo *certInfo, const X509CertInfo *issuerCertInfo, const uint8_t *nonce, size_t nonceLen)
OCSP response validation.
Subject Public Key Information extension.
Definition: x509_common.h:790
ResponderID structure.
Definition: ocsp_common.h:238
CertID structure.
Definition: ocsp_common.h:142
#define cryptoFreeMem(p)
Definition: crypto.h:791
X509OctetString signature
Definition: ocsp_common.h:278
OcspExtensions responseExtensions
Definition: ocsp_common.h:256
OCSP response validation.
@ ERROR_WRONG_IDENTIFIER
Definition: error.h:89
#define cryptoAllocMem(size)
Definition: crypto.h:786
@ X509_EXT_KEY_USAGE_OCSP_SIGNING
Definition: x509_common.h:504
X.509 certificate validation.
X.509 certificate extensions.
Definition: x509_common.h:1003
X509OctetString rawSubjectPublicKey
Definition: x509_common.h:793
SingleResponse structure.
Definition: ocsp_common.h:223
const uint8_t * value
Definition: x509_common.h:654
Common interface for hash algorithms.
Definition: crypto.h:1046
X509SubjectPublicKeyInfo subjectPublicKeyInfo
Definition: x509_common.h:1061
@ OCSP_RESP_STATUS_SUCCESSFUL
Response has valid confirmations.
Definition: ocsp_common.h:116
OcspResponseStatus responseStatus
Definition: ocsp_common.h:290
@ ERROR_INVALID_RESPONSE
Definition: error.h:71
OCSPResponse structure.
Definition: ocsp_common.h:288
OcspCertId certId
Definition: ocsp_common.h:224
__weak_func time_t getCurrentUnixTime(void)
Get current time.
Definition: date_time.c:180
X509OctetString raw
Definition: x509_common.h:676
uint8_t nonce[]
Definition: ntp_common.h:233
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
ASN.1 (Abstract Syntax Notation One)
@ ERROR_WRONG_NONCE
Definition: error.h:303
error_t ocspCheckResponseSignature(const OcspBasicResponse *basicResponse, const X509CertInfo *issuerCertInfo)
Verify response signature.
int_t compareDateTime(const DateTime *date1, const DateTime *date2)
Compare dates.
Definition: date_time.c:304