1 /****************************************************************************
2 * *
3 * Set Certificate Components *
4 * Copyright Peter Gutmann 1997-2012 *
5 * *
6 ****************************************************************************/
7
8 #if defined( INC_ALL )
9 #include "cert.h"
10 #include "certattr.h"
11 #include "asn1_ext.h"
12 #else
13 #include "cert/cert.h"
14 #include "cert/certattr.h"
15 #include "enc_dec/asn1_ext.h"
16 #endif /* Compiler-specific includes */
17
18 #ifdef USE_CERTIFICATES
19
20 /* Determine whether anyone ever uses the higher compliance levels */
21
22 #if defined( USE_CERTLEVEL_PKIX_FULL )
23 #error If you see this message, please let the cryptlib developers know,
24 #error then remove the error directive that caused it and recompile as normal.
25 #endif /* USE_CERTLEVEL_PKIX_FULL */
26
27 /****************************************************************************
28 * *
29 * Utility Routines *
30 * *
31 ****************************************************************************/
32
33 #if defined( USE_CERTREQ ) || defined( USE_CERTREV )
34
35 /* Copy the encoded issuer DN */
36
37 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyIssuerDnData(INOUT CERT_INFO * destCertInfoPtr,const CERT_INFO * srcCertInfoPtr)38 static int copyIssuerDnData( INOUT CERT_INFO *destCertInfoPtr,
39 const CERT_INFO *srcCertInfoPtr )
40 {
41 void *dnDataPtr;
42
43 assert( isWritePtr( destCertInfoPtr, sizeof( CERT_INFO ) ) );
44 assert( isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) );
45
46 REQUIRES( destCertInfoPtr->issuerDNptr == NULL );
47 REQUIRES( srcCertInfoPtr->issuerDNptr != NULL );
48
49 if( ( dnDataPtr = clAlloc( "copyIssuerDnData",
50 srcCertInfoPtr->issuerDNsize ) ) == NULL )
51 return( CRYPT_ERROR_MEMORY );
52 memcpy( dnDataPtr, srcCertInfoPtr->issuerDNptr,
53 srcCertInfoPtr->issuerDNsize );
54 destCertInfoPtr->issuerDNptr = destCertInfoPtr->issuerDNdata = dnDataPtr;
55 destCertInfoPtr->issuerDNsize = srcCertInfoPtr->issuerDNsize;
56
57 return( CRYPT_OK );
58 }
59
60 /* Copy revocation information into a CRL or revocation request */
61
62 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyRevocationInfo(INOUT CERT_INFO * certInfoPtr,const CERT_INFO * revInfoPtr)63 static int copyRevocationInfo( INOUT CERT_INFO *certInfoPtr,
64 const CERT_INFO *revInfoPtr )
65 {
66 const void *serialNumberPtr;
67 int serialNumberLength, status = CRYPT_OK;
68
69 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
70 assert( isReadPtr( revInfoPtr, sizeof( CERT_INFO ) ) );
71 assert( isReadPtr( revInfoPtr->issuerDNptr,
72 revInfoPtr->issuerDNsize ) );
73
74 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
75 certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
76 REQUIRES( revInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
77 revInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
78 revInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
79 revInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
80 REQUIRES( revInfoPtr->issuerDNptr != NULL );
81
82 /* If there's an issuer name recorded make sure that it matches the one
83 in the certificate that's being added */
84 if( certInfoPtr->issuerDNptr != NULL )
85 {
86 if( certInfoPtr->issuerDNsize != revInfoPtr->issuerDNsize || \
87 memcmp( certInfoPtr->issuerDNptr, revInfoPtr->issuerDNptr,
88 certInfoPtr->issuerDNsize ) )
89 {
90 setErrorInfo( certInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
91 CRYPT_ERRTYPE_ATTR_VALUE );
92 status = CRYPT_ERROR_INVALID;
93 }
94 }
95 else
96 {
97 /* There's no issuer name present yet, set the CRL issuer name to
98 the certificate's issuer to make sure that we can't add
99 certificates or sign the CRL with a different issuer. We do this
100 here rather than after setting the revocation list entry because
101 of the difficulty of undoing the revocation entry addition */
102 status = copyIssuerDnData( certInfoPtr, revInfoPtr );
103 }
104 if( cryptStatusError( status ) )
105 return( status );
106
107 /* Add the certificate information to the revocation list and make it
108 the currently selected entry. The ID type isn't quite an
109 issuerAndSerialNumber but the checking code eventually converts it
110 into this form using the supplied issuer certificate DN */
111 if( revInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
112 {
113 serialNumberPtr = revInfoPtr->cCertReq->serialNumber;
114 serialNumberLength = revInfoPtr->cCertReq->serialNumberLength;
115 }
116 else
117 {
118 serialNumberPtr = revInfoPtr->cCertCert->serialNumber;
119 serialNumberLength = revInfoPtr->cCertCert->serialNumberLength;
120 }
121 status = addRevocationEntry( &certInfoPtr->cCertRev->revocations,
122 &certInfoPtr->cCertRev->currentRevocation,
123 CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
124 serialNumberPtr, serialNumberLength, FALSE );
125 if( status == CRYPT_ERROR_DUPLICATE )
126 {
127 /* If this certificate is already present in the list set the
128 extended error code for it */
129 setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
130 CRYPT_ERRTYPE_ATTR_PRESENT );
131 }
132 return( status );
133 }
134 #endif /* USE_CERTREQ || USE_CERTREV */
135
136 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
137
138 /* Copy an RTCS or OCSP responder URL from a certificate into a request */
139
140 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyResponderURL(INOUT CERT_INFO * requestInfoPtr,INOUT CERT_INFO * userCertInfoPtr)141 static int copyResponderURL( INOUT CERT_INFO *requestInfoPtr,
142 INOUT CERT_INFO *userCertInfoPtr )
143 {
144 const CRYPT_ATTRIBUTE_TYPE aiaAttribute = \
145 ( requestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST ) ? \
146 CRYPT_CERTINFO_AUTHORITYINFO_RTCS : \
147 CRYPT_CERTINFO_AUTHORITYINFO_OCSP;
148 SELECTION_STATE savedState;
149 void *responderUrl;
150 int urlSize DUMMY_INIT, status;
151
152 REQUIRES( requestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
153 requestInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
154 REQUIRES( userCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
155 userCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
156
157 /* There's no responder URL set, check whether the user certificate
158 contains a responder URL in the RTCS/OCSP authorityInfoAccess
159 GeneralName */
160 saveSelectionState( savedState, userCertInfoPtr );
161 status = selectGeneralName( userCertInfoPtr, aiaAttribute,
162 MAY_BE_ABSENT );
163 if( cryptStatusOK( status ) )
164 {
165 status = selectGeneralName( userCertInfoPtr,
166 CRYPT_ATTRIBUTE_NONE,
167 MUST_BE_PRESENT );
168 }
169 if( cryptStatusOK( status ) )
170 {
171 status = getCertComponentString( userCertInfoPtr,
172 CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER,
173 NULL, 0, &urlSize );
174 }
175 if( cryptStatusError( status ) )
176 {
177 /* If there's no responder URL present then it's not a (fatal)
178 error */
179 restoreSelectionState( savedState, userCertInfoPtr );
180 return( CRYPT_OK );
181 }
182
183 /* There's a responder URL present, copy it to the request */
184 if( ( responderUrl = clAlloc( "copyResponderURL", urlSize ) ) == NULL )
185 {
186 restoreSelectionState( savedState, userCertInfoPtr );
187 return( CRYPT_ERROR_MEMORY );
188 }
189 status = getCertComponentString( userCertInfoPtr,
190 CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER,
191 responderUrl, urlSize, &urlSize );
192 if( cryptStatusOK( status ) )
193 {
194 if( requestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST )
195 {
196 REQUIRES( requestInfoPtr->cCertVal->responderUrl == NULL );
197
198 requestInfoPtr->cCertVal->responderUrl = responderUrl;
199 requestInfoPtr->cCertVal->responderUrlSize = urlSize;
200 }
201 else
202 {
203 REQUIRES( requestInfoPtr->cCertRev->responderUrl == NULL );
204
205 requestInfoPtr->cCertRev->responderUrl = responderUrl;
206 requestInfoPtr->cCertRev->responderUrlSize = urlSize;
207 }
208 }
209 else
210 {
211 clFree( "copyResponderURL", responderUrl );
212 }
213 restoreSelectionState( savedState, userCertInfoPtr );
214
215 return( status );
216 }
217 #endif /* USE_CERTREV || USE_CERTVAL */
218
219 /****************************************************************************
220 * *
221 * Copy Certificate Data *
222 * *
223 ****************************************************************************/
224
225 /* Check that the key in a XYZZY certificate is signature-capable (or at
226 least sig-check capable, since it may be just the public key that's being
227 used), since XYZZY certificates are self-signed. Then set the
228 appropriate signature keyUsage and optional encryption usage if the key
229 can also do that */
230
231 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
setXyzzyKeyUsage(INOUT CERT_INFO * certInfoPtr,IN_HANDLE const CRYPT_CONTEXT iCryptContext)232 static int setXyzzyKeyUsage( INOUT CERT_INFO *certInfoPtr,
233 IN_HANDLE const CRYPT_CONTEXT iCryptContext )
234 {
235 int keyUsage = KEYUSAGE_SIGN | KEYUSAGE_CA, status;
236
237 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
238
239 REQUIRES( isHandleRangeValid( iCryptContext ) );
240
241 /* Make sure that the key is signature-capable. We have to check for a
242 capability to either sign or sig-check since a pure public key will
243 only have a sig-check capability while a private key held in a device
244 (from which we're going to extract the public-key components) may be
245 only signature-capable */
246 status = krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
247 MESSAGE_CHECK_PKC_SIGCHECK );
248 if( cryptStatusError( status ) )
249 status = krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
250 MESSAGE_CHECK_PKC_SIGN );
251 if( cryptStatusError( status ) )
252 {
253 setErrorInfo( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
254 CRYPT_ERRTYPE_ATTR_VALUE );
255 return( CRYPT_ERROR_INVALID );
256 }
257
258 /* If the key is encryption-capable (with the same caveat as for the
259 signature check above), enable that usage as well */
260 status = krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
261 MESSAGE_CHECK_PKC_ENCRYPT );
262 if( cryptStatusError( status ) )
263 status = krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
264 MESSAGE_CHECK_PKC_DECRYPT );
265 if( cryptStatusOK( status ) )
266 keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
267
268 /* Clear the existing usage and replace it with our usage. See the
269 comment in setXyzzyInfo() for why it's done this way */
270 ( void ) deleteCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE );
271 return( addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
272 keyUsage ) );
273 }
274
275 /* Copy public key data into a certificate object */
276
277 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
copyKeyFromCertificate(INOUT CERT_INFO * destCertInfoPtr,const CERT_INFO * srcCertInfoPtr)278 static int copyKeyFromCertificate( INOUT CERT_INFO *destCertInfoPtr,
279 const CERT_INFO *srcCertInfoPtr )
280 {
281 void *publicKeyInfoPtr;
282
283 assert( isWritePtr( destCertInfoPtr, sizeof( CERT_INFO ) ) );
284 assert( isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) );
285
286 REQUIRES( destCertInfoPtr->publicKeyInfo == NULL );
287 REQUIRES( srcCertInfoPtr->publicKeyInfo != NULL );
288
289 if( ( publicKeyInfoPtr = \
290 clAlloc( "copyPublicKeyInfo",
291 srcCertInfoPtr->publicKeyInfoSize ) ) == NULL )
292 return( CRYPT_ERROR_MEMORY );
293 memcpy( publicKeyInfoPtr, srcCertInfoPtr->publicKeyInfo,
294 srcCertInfoPtr->publicKeyInfoSize );
295 destCertInfoPtr->publicKeyData = destCertInfoPtr->publicKeyInfo = \
296 publicKeyInfoPtr;
297 destCertInfoPtr->publicKeyInfoSize = srcCertInfoPtr->publicKeyInfoSize;
298 destCertInfoPtr->publicKeyAlgo = srcCertInfoPtr->publicKeyAlgo;
299 destCertInfoPtr->publicKeyFeatures = srcCertInfoPtr->publicKeyFeatures;
300 memcpy( destCertInfoPtr->publicKeyID, srcCertInfoPtr->publicKeyID,
301 KEYID_SIZE );
302 destCertInfoPtr->flags |= CERT_FLAG_DATAONLY;
303
304 return( CRYPT_OK );
305 }
306
307 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
copyKeyFromContext(INOUT CERT_INFO * destCertInfoPtr,IN_HANDLE const CRYPT_CONTEXT iCryptContext)308 static int copyKeyFromContext( INOUT CERT_INFO *destCertInfoPtr,
309 IN_HANDLE const CRYPT_CONTEXT iCryptContext )
310 {
311 MESSAGE_DATA msgData;
312 void *publicKeyInfoPtr;
313 int length, status;
314
315 assert( isWritePtr( destCertInfoPtr, sizeof( CERT_INFO ) ) );
316
317 REQUIRES( destCertInfoPtr->publicKeyInfo == NULL );
318 REQUIRES( isHandleRangeValid( iCryptContext ) );
319
320 /* Get the key metadata from the context */
321 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
322 &destCertInfoPtr->publicKeyAlgo,
323 CRYPT_CTXINFO_ALGO );
324 if( cryptStatusOK( status ) )
325 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
326 &destCertInfoPtr->publicKeyFeatures,
327 CRYPT_IATTRIBUTE_KEYFEATURES );
328 if( cryptStatusOK( status ) )
329 {
330 setMessageData( &msgData, destCertInfoPtr->publicKeyID, KEYID_SIZE );
331 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
332 &msgData, CRYPT_IATTRIBUTE_KEYID );
333 }
334 if( cryptStatusError( status ) )
335 return( status );
336
337 /* Copy over the public-key data. We perform a copy rather than keeping
338 a reference to the context for two reasons. Firstly, when the
339 certificate is transitioned into the high state it will constrain the
340 attached context so a context shared between two certificates could
341 be constrained in unexpected ways. Secondly, the context could be a
342 private-key context and attaching that to a certificate would be
343 rather inappropriate. Furthermore, the constraint issue is even more
344 problematic in that a context constrained by an encryption-only
345 request could then no longer be used to sign the request or a PKI
346 protocol message containing the request */
347 setMessageData( &msgData, NULL, 0 );
348 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
349 &msgData, CRYPT_IATTRIBUTE_KEY_SPKI );
350 if( cryptStatusError( status ) )
351 return( status );
352 length = msgData.length;
353 if( ( publicKeyInfoPtr = clAlloc( "copyPublicKeyInfo",
354 length ) ) == NULL )
355 return( CRYPT_ERROR_MEMORY );
356 setMessageData( &msgData, publicKeyInfoPtr, length );
357 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
358 &msgData, CRYPT_IATTRIBUTE_KEY_SPKI );
359 if( cryptStatusError( status ) )
360 return( status );
361 destCertInfoPtr->publicKeyData = destCertInfoPtr->publicKeyInfo = \
362 publicKeyInfoPtr;
363 destCertInfoPtr->publicKeyInfoSize = length;
364 destCertInfoPtr->flags |= CERT_FLAG_DATAONLY;
365
366 return( CRYPT_OK );
367 }
368
369 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
copyPublicKeyInfo(INOUT CERT_INFO * certInfoPtr,IN_HANDLE_OPT const CRYPT_HANDLE cryptHandle,IN_OPT const CERT_INFO * srcCertInfoPtr)370 int copyPublicKeyInfo( INOUT CERT_INFO *certInfoPtr,
371 IN_HANDLE_OPT const CRYPT_HANDLE cryptHandle,
372 IN_OPT const CERT_INFO *srcCertInfoPtr )
373 {
374 CRYPT_CONTEXT iCryptContext;
375 int isXyzzyCert, status;
376
377 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
378 assert( ( isHandleRangeValid( cryptHandle ) && \
379 srcCertInfoPtr == NULL ) || \
380 ( cryptHandle == CRYPT_UNUSED && \
381 isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) ) );
382
383 REQUIRES( ( isHandleRangeValid( cryptHandle ) && \
384 srcCertInfoPtr == NULL ) || \
385 ( cryptHandle == CRYPT_UNUSED && \
386 srcCertInfoPtr != NULL ) );
387 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
388 certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
389 certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
390 certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
391 certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
392 REQUIRES( srcCertInfoPtr == NULL || \
393 srcCertInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
394 srcCertInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
395
396 /* Make sure that we haven't already got a public key present */
397 if( certInfoPtr->iPubkeyContext != CRYPT_ERROR || \
398 certInfoPtr->publicKeyInfo != NULL )
399 {
400 setErrorInfo( certInfoPtr, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
401 CRYPT_ERRTYPE_ATTR_PRESENT );
402 return( CRYPT_ERROR_INITED );
403 }
404
405 /* If we've been given a data-only certificate then all that we need to
406 do is copy over the public key data */
407 if( srcCertInfoPtr != NULL )
408 return( copyKeyFromCertificate( certInfoPtr, srcCertInfoPtr ) );
409
410 /* Get the context handle. All other checking has already been
411 performed by the kernel */
412 status = krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT,
413 &iCryptContext, OBJECT_TYPE_CONTEXT );
414 if( cryptStatusError( status ) )
415 {
416 setErrorInfo( certInfoPtr, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
417 CRYPT_ERRTYPE_ATTR_VALUE );
418 return( status );
419 }
420
421 /* If it's a XYZZY certificate then we need to perform additional
422 processing for XYZZY-specific key usage requirements */
423 status = getCertComponent( certInfoPtr, CRYPT_CERTINFO_XYZZY,
424 &isXyzzyCert );
425 if( cryptStatusOK( status ) && isXyzzyCert )
426 {
427 status = setXyzzyKeyUsage( certInfoPtr, iCryptContext);
428 if( cryptStatusError( status ) )
429 return( status );
430 }
431
432 /* Copy the public-key data from the encryption context */
433 return( copyKeyFromContext( certInfoPtr, iCryptContext ) );
434 }
435
436 #ifdef USE_DBMS /* Only used by CA code */
437
438 /* Sanitise certificate attributes based on a user-supplied template. This
439 is used to prevent a user from supplying potentially dangerous attributes
440 in a certificate request, for example to request a CA certificate by
441 setting the basicConstraints/keyUsage = CA extensions in the request in a
442 manner that would result in the creation of a CA certificate when the
443 request is processed.
444
445 There are two ways to do this, either with a whitelist or with a
446 blacklist. Obviously the preferred option is the whitelist one, but the
447 problem with this is that without any knowledge of the environment into
448 which it's being deployed we have no idea what should be permitted. For
449 example an RA, which acts as a trusted agent for the CA, probably wants
450 fuller control over the form of the certificate with a wider selection of
451 attributes permitted while a CA dealing directly with the public probably
452 wants few or no attributes permitted. This is a variation of the
453 firewall configuration problem, lock it down by default and users will
454 complain, leave it open by default and users are happy but it's not secure.
455
456 What we use here is in effect a blend of whitelist and blacklist. On
457 the whitelist side the only attributes that are permitted in certificate
458 requests are:
459
460 CRYPT_CERTINFO_CHALLENGEPASSWORD: Needed for SCEP.
461 CRYPT_CERTINFO_KEYFEATURES: Only used by cryptlib for its own purposes.
462 CRYPT_CERTINFO_KEYUSAGE
463 CRYPT_CERTINFO_SUBJECTALTNAME
464 CRYPT_CERTINFO_EXTKEYUSAGE
465
466 For revocation requests we allow rather more values since they're
467 required by the client to inform the CA why the certificate is being
468 revoked. Except for the invalidity date they're not so much of a
469 security threat, and even for the date the consistency vs. accuracy issue
470 for CRLs debate means the CA will put who knows what date in the CRL
471 anyway:
472
473 CRYPT_CERTINFO_CRLEXTREASON
474 CRYPT_CERTINFO_CRLREASON
475 CRYPT_CERTINFO_HOLDINSTRUCTIONCODE
476 CRYPT_CERTINFO_INVALIDITYDATE
477
478 Everything else, including the all-important basicConstraints, has to be
479 set explicitly by the CA and can't be specified in a request.
480
481 On the blacklist side, multi-AVA RDNs are disallowed in order to prevent
482 an attacker from playing games with DN forms. This should be safe
483 because the only things that create such weird DNs tend to be European
484 in-house CAs following (or justifying their bugs through) peculiar
485 requirements in digital signature legislation, and those guys will be
486 creating their own certificates from scratch themselves rather than using
487 cryptlib for it */
488
489 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
checkCertWellFormed(INOUT CERT_INFO * certInfoPtr)490 static int checkCertWellFormed( INOUT CERT_INFO *certInfoPtr )
491 {
492 ATTRIBUTE_PTR *attributePtr;
493 int status;
494
495 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
496
497 /* Check that the subject DN is well-formed */
498 status = checkDN( certInfoPtr->subjectName,
499 CHECKDN_FLAG_COUNTRY | CHECKDN_FLAG_COMMONNAME | \
500 CHECKDN_FLAG_WELLFORMED,
501 &certInfoPtr->errorLocus,
502 &certInfoPtr->errorType );
503 if( cryptStatusError( status ) )
504 return( status );
505
506 /* There can potentially be any number of other DNs in a certificate
507 (typically hidden in GeneralName fields), it's not really certain
508 what we should do with these or even how we can effectively track
509 them all down. Since the reason why we're doing this in the first
510 place is to avoid shenanigans due to the more or less arbitrary
511 handling of complex DNs by implementations, and the only one that
512 anyone really pays any attention to is the subject name, we check
513 the subject name and at least have a go at the subjectAltName, but
514 leave the rest (it's not even certain what a DN in, say, an AIA
515 would mean, let alone how to check it) */
516 attributePtr = findAttribute( certInfoPtr->attributes,
517 CRYPT_CERTINFO_SUBJECTALTNAME, TRUE );
518 if( attributePtr != NULL )
519 attributePtr = findAttributeField( attributePtr,
520 CRYPT_CERTINFO_SUBJECTALTNAME,
521 CRYPT_CERTINFO_DIRECTORYNAME );
522 if( attributePtr != NULL )
523 {
524 CRYPT_ATTRIBUTE_TYPE dummy1;
525 CRYPT_ERRTYPE_TYPE dummy2;
526 DN_PTR **dnPtr;
527
528 status = getAttributeDataDN( attributePtr, &dnPtr );
529 if( cryptStatusOK( status ) )
530 {
531 status = checkDN( dnPtr, CHECKDN_FLAG_COUNTRY | \
532 CHECKDN_FLAG_COMMONNAME | \
533 CHECKDN_FLAG_WELLFORMED,
534 &dummy1, &dummy2 );
535 if( cryptStatusError( status ) )
536 {
537 /* Reporting this one is a bit complicated because we're
538 dealing with a complex nested attribute, the best that we
539 can do is report a general problem with the altName */
540 setErrorInfo( certInfoPtr,
541 CRYPT_CERTINFO_SUBJECTALTNAME,
542 CRYPT_ERRTYPE_ATTR_VALUE );
543 return( status );
544 }
545 }
546 }
547
548 return( CRYPT_OK );
549 }
550
551 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sanitiseCertAttributes(INOUT CERT_INFO * certInfoPtr,IN_OPT const ATTRIBUTE_PTR * templateListPtr)552 static int sanitiseCertAttributes( INOUT CERT_INFO *certInfoPtr,
553 IN_OPT const ATTRIBUTE_PTR *templateListPtr )
554 {
555 const ATTRIBUTE_PTR *templateAttributeCursor;
556 ATTRIBUTE_ENUM_INFO attrEnumInfo;
557 int iterationCount;
558
559 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
560 assert( templateListPtr == NULL || \
561 ( isReadPtr( templateListPtr, sizeof( ATTRIBUTE_PTR_STORAGE ) ) ) );
562
563 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
564 certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
565 certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
566
567 /* If there are no attributes present or there's no disallowed-attribute
568 template, we just need to apply the well-formedness check on the way
569 out */
570 if( certInfoPtr->attributes == NULL || templateListPtr == NULL )
571 return( checkCertWellFormed( certInfoPtr ) );
572
573 /* Walk down the template attribute list applying each one in turn to
574 the certificate attributes */
575 for( templateAttributeCursor = \
576 getFirstAttribute( &attrEnumInfo, templateListPtr, \
577 ATTRIBUTE_ENUM_NONBLOB ), \
578 iterationCount = 0;
579 templateAttributeCursor != NULL && \
580 iterationCount < FAILSAFE_ITERATIONS_MAX;
581 templateAttributeCursor = getNextAttribute( &attrEnumInfo ), \
582 iterationCount++ )
583 {
584 CRYPT_ATTRIBUTE_TYPE fieldID, subFieldID;
585 ATTRIBUTE_PTR *certAttributePtr;
586 int status;
587
588 /* Check to see whether there's a constrained attribute present in
589 the certificate attributes and if it is, whether it conflicts
590 with the constraining attribute */
591 status = getAttributeIdInfo( templateAttributeCursor, NULL,
592 &fieldID, &subFieldID );
593 if( cryptStatusError( status ) )
594 return( status );
595 certAttributePtr = findAttributeField( certInfoPtr->attributes,
596 fieldID, subFieldID );
597 if( certAttributePtr == NULL )
598 {
599 /* There's nothing to constrain present in the certificate,
600 continue */
601 continue;
602 }
603
604 /* If the certificate attribute was provided through the application
605 of PKI user data (indicated by it having the locked flag set),
606 allow it even if it conflicts with the constraining attribute.
607 This is permitted because the PKI user data was explicitly set by
608 the issuing CA rather than being user-supplied in the certificate
609 request so it has to be OK, or at least CA-approved */
610 if( checkAttributeProperty( certAttributePtr,
611 ATTRIBUTE_PROPERTY_LOCKED ) )
612 continue;
613
614 /* There are conflicting attributes present, disallow the
615 certificate issue */
616 status = getAttributeIdInfo( certAttributePtr, NULL, &fieldID,
617 NULL );
618 if( cryptStatusError( status ) )
619 return( status );
620 if( fieldID == CRYPT_CERTINFO_KEYUSAGE )
621 {
622 int constrainedAttributeValue, constrainingAttributeValue;
623
624 /* There is one special case in which conflicting attributes
625 are allowed and that's for keyUsage (or more generally
626 bitfields), since we can selectively disallow dangerous bit
627 values while allowing safe ones */
628 status = getAttributeDataValue( certAttributePtr,
629 &constrainedAttributeValue );
630 if( cryptStatusError( status ) )
631 return( status );
632 status = getAttributeDataValue( templateAttributeCursor,
633 &constrainingAttributeValue );
634 if( cryptStatusError( status ) )
635 return( status );
636 if( !( constrainedAttributeValue & constrainingAttributeValue ) )
637 continue;
638 }
639 certInfoPtr->errorLocus = fieldID;
640 certInfoPtr->errorType = CRYPT_ERRTYPE_ATTR_VALUE;
641 return( CRYPT_ERROR_INVALID );
642 }
643 ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
644
645 return( checkCertWellFormed( certInfoPtr ) );
646 }
647 #endif /* USE_DBMS*/
648
649 /****************************************************************************
650 * *
651 * Copy Certificate Request Data *
652 * *
653 ****************************************************************************/
654
655 #ifdef USE_CERTREQ
656
657 /* Copy certificate request information into a certificate object. This
658 copies the public key context, the DN, any valid attributes, and any other
659 relevant bits and pieces if it's a CRMF request */
660
661 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyCertReqToCert(INOUT CERT_INFO * certInfoPtr,INOUT CERT_INFO * certRequestInfoPtr)662 static int copyCertReqToCert( INOUT CERT_INFO *certInfoPtr,
663 INOUT CERT_INFO *certRequestInfoPtr )
664 {
665 int status;
666
667 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
668 assert( isWritePtr( certRequestInfoPtr, sizeof( CERT_INFO ) ) );
669
670 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
671 certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
672 certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
673 REQUIRES( certInfoPtr->subjectName == NULL );
674 REQUIRES( certRequestInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
675 certRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
676
677 /* Copy the public key context, the DN, and the attributes. Type
678 checking has already been performed by the kernel. We copy the
679 attributes across after the DN because that copy is the hardest to
680 undo: If there are already attributes present then the copied
681 attributes would be mixed in among them so it's not really possible
682 to undo the copy later without performing a complex selective
683 delete */
684 status = copyDN( &certInfoPtr->subjectName,
685 certRequestInfoPtr->subjectName );
686 if( cryptStatusError( status ) )
687 return( status );
688 if( certRequestInfoPtr->flags & CERT_FLAG_DATAONLY )
689 {
690 status = copyPublicKeyInfo( certInfoPtr, CRYPT_UNUSED,
691 certRequestInfoPtr );
692 }
693 else
694 {
695 status = copyPublicKeyInfo( certInfoPtr,
696 certRequestInfoPtr->iPubkeyContext,
697 NULL );
698 }
699 if( cryptStatusOK( status ) && \
700 certRequestInfoPtr->attributes != NULL )
701 {
702 status = copyAttributes( &certInfoPtr->attributes,
703 certRequestInfoPtr->attributes,
704 &certInfoPtr->errorLocus,
705 &certInfoPtr->errorType );
706 }
707 if( cryptStatusError( status ) )
708 {
709 deleteDN( &certInfoPtr->subjectName );
710 return( status );
711 }
712
713 /* If it's a CRMF request there could also be a validity period
714 specified */
715 if( certRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
716 {
717 const time_t currentTime = getApproxTime();
718
719 /* We don't allow start times backdated by more than a year or end
720 times before the start time. Since these are trivial things we
721 don't abort if there's a problem but just quietly fix the value */
722 if( certRequestInfoPtr->startTime > MIN_TIME_VALUE && \
723 certRequestInfoPtr->startTime > currentTime - ( 86400L * 365 ) )
724 certInfoPtr->startTime = certRequestInfoPtr->startTime;
725 if( certRequestInfoPtr->endTime > MIN_TIME_VALUE && \
726 certRequestInfoPtr->endTime > certInfoPtr->startTime )
727 certInfoPtr->endTime = certRequestInfoPtr->endTime;
728 }
729
730 return( CRYPT_OK );
731 }
732
733 /* Copy what we need to identify the certificate to be revoked and any
734 revocation information into a certificate object */
735
736 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyRevReqToCert(INOUT CERT_INFO * certInfoPtr,INOUT CERT_INFO * revRequestInfoPtr)737 static int copyRevReqToCert( INOUT CERT_INFO *certInfoPtr,
738 INOUT CERT_INFO *revRequestInfoPtr )
739 {
740 int status;
741
742 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
743 assert( isWritePtr( revRequestInfoPtr, sizeof( CERT_INFO ) ) );
744
745 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CRL );
746 REQUIRES( revRequestInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
747 revRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
748
749 status = copyRevocationInfo( certInfoPtr, revRequestInfoPtr );
750 if( cryptStatusError( status ) || \
751 revRequestInfoPtr->attributes == NULL )
752 return( status );
753 return( copyRevocationAttributes( &certInfoPtr->attributes,
754 revRequestInfoPtr->attributes ) );
755 }
756
757 /* Copy the public key, DN, and any attributes that need to be copied across.
758 We copy the full DN rather than just the encoded form in case the user
759 wants to query the request details after creating it */
760
761 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyCertToRequest(INOUT CERT_INFO * crmfRequestInfoPtr,INOUT CERT_INFO * certInfoPtr,const CRYPT_HANDLE iCryptHandle)762 static int copyCertToRequest( INOUT CERT_INFO *crmfRequestInfoPtr,
763 INOUT CERT_INFO *certInfoPtr,
764 const CRYPT_HANDLE iCryptHandle )
765 {
766 int status;
767
768 assert( isWritePtr( crmfRequestInfoPtr, sizeof( CERT_INFO ) ) );
769 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
770
771 REQUIRES( crmfRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
772 REQUIRES( crmfRequestInfoPtr->subjectName == NULL );
773 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
774 certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
775 certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
776
777 status = copyDN( &crmfRequestInfoPtr->subjectName,
778 certInfoPtr->subjectName );
779 if( cryptStatusError( status ) )
780 return( status );
781 if( crmfRequestInfoPtr->iPubkeyContext == CRYPT_ERROR && \
782 crmfRequestInfoPtr->publicKeyInfo == NULL )
783 {
784 /* Only copy the key across if a key hasn't already been added
785 earlier as CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO. Checking for
786 this special case (rather than returning an error) allows the DN
787 information from an existing certificate to be copied into a
788 request for a new key */
789 status = copyPublicKeyInfo( crmfRequestInfoPtr, iCryptHandle, NULL );
790 }
791 if( cryptStatusOK( status ) )
792 {
793 /* We copy the attributes across after the DN because that copy is
794 the hardest to undo: If there are already attributes present then
795 the copied attributes will be mixed in among them so it's not
796 really possible to undo the copy later without performing a
797 complex selective delete */
798 status = copyCRMFRequestAttributes( &crmfRequestInfoPtr->attributes,
799 certInfoPtr->attributes );
800 }
801 if( cryptStatusError( status ) )
802 deleteDN( &crmfRequestInfoPtr->subjectName );
803
804 return( status );
805 }
806
807 /* Copy across the issuer and subject DN and serial number */
808
809 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyCertToRevRequest(INOUT CERT_INFO * crmfRevRequestInfoPtr,INOUT CERT_INFO * certInfoPtr)810 static int copyCertToRevRequest( INOUT CERT_INFO *crmfRevRequestInfoPtr,
811 INOUT CERT_INFO *certInfoPtr )
812 {
813 int status;
814
815 assert( isWritePtr( crmfRevRequestInfoPtr, sizeof( CERT_INFO ) ) );
816 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
817
818 REQUIRES( crmfRevRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
819 REQUIRES( crmfRevRequestInfoPtr->subjectName == NULL );
820 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
821 certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
822 certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
823
824 /* If the information is already present then we can't add it again */
825 if( crmfRevRequestInfoPtr->issuerName != NULL )
826 {
827 setErrorInfo( crmfRevRequestInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
828 CRYPT_ERRTYPE_ATTR_PRESENT );
829 return( CRYPT_ERROR_INITED );
830 }
831
832 /* Copy across the issuer name and allocate the storage that we need to
833 copy the subject name. We don't care about any internal structure of
834 the DNs so we just copy the pre-encoded form, we could in theory copy
835 the full DN but it isn't really the issuer (creator) of the object so
836 it's better if it appears to have no issuer DN than a misleading one */
837 status = copyIssuerDnData( crmfRevRequestInfoPtr, certInfoPtr );
838 if( cryptStatusError( status ) )
839 return( status );
840 status = setSerialNumber( crmfRevRequestInfoPtr,
841 certInfoPtr->cCertCert->serialNumber,
842 certInfoPtr->cCertCert->serialNumberLength );
843 if( cryptStatusOK( status ) && \
844 ( crmfRevRequestInfoPtr->subjectDNdata = \
845 clAlloc( "copyCertToRevRequest",
846 certInfoPtr->subjectDNsize ) ) == NULL )
847 status = CRYPT_ERROR_MEMORY;
848 if( cryptStatusError( status ) )
849 {
850 clFree( "copyCertToRevRequest",
851 crmfRevRequestInfoPtr->issuerDNdata );
852 crmfRevRequestInfoPtr->issuerDNptr = \
853 crmfRevRequestInfoPtr->issuerDNdata = NULL;
854 crmfRevRequestInfoPtr->issuerDNsize = 0;
855 if( crmfRevRequestInfoPtr->cCertCert->serialNumber != NULL && \
856 crmfRevRequestInfoPtr->cCertCert->serialNumber != \
857 crmfRevRequestInfoPtr->cCertCert->serialNumberBuffer )
858 {
859 clFree( "copyCertToRevRequest",
860 crmfRevRequestInfoPtr->cCertCert->serialNumber );
861 }
862 crmfRevRequestInfoPtr->cCertCert->serialNumber = NULL;
863 crmfRevRequestInfoPtr->cCertCert->serialNumberLength = 0;
864 return( status );
865 }
866
867 /* Copy the subject DN for use in CMP */
868 memcpy( crmfRevRequestInfoPtr->subjectDNdata, certInfoPtr->subjectDNptr,
869 certInfoPtr->subjectDNsize );
870 crmfRevRequestInfoPtr->subjectDNptr = crmfRevRequestInfoPtr->subjectDNdata;
871 crmfRevRequestInfoPtr->subjectDNsize = certInfoPtr->subjectDNsize;
872
873 return( CRYPT_OK );
874 }
875 #endif /* USE_CERTREQ */
876
877 /****************************************************************************
878 * *
879 * Copy Certificate Revocation Data *
880 * *
881 ****************************************************************************/
882
883 #ifdef USE_CERTREV
884
885 /* The OCSP ID doesn't contain any usable fields so we pre-encode it when
886 the certificate is added to the OCSP request and treat it as a blob
887 thereafter */
888
889 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
writeOCSPID(INOUT STREAM * stream,const CERT_INFO * certInfoPtr,IN_BUFFER (issuerKeyHashLength)const void * issuerKeyHash,IN_LENGTH_FIXED (KEYID_SIZE)const int issuerKeyHashLength)890 static int writeOCSPID( INOUT STREAM *stream,
891 const CERT_INFO *certInfoPtr,
892 IN_BUFFER( issuerKeyHashLength ) \
893 const void *issuerKeyHash,
894 IN_LENGTH_FIXED( KEYID_SIZE ) \
895 const int issuerKeyHashLength )
896 {
897 HASH_FUNCTION_ATOMIC hashFunctionAtomic;
898 BYTE hashBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
899 int hashSize;
900
901 assert( isWritePtr( stream, sizeof( STREAM ) ) );
902 assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
903 assert( isReadPtr( issuerKeyHash, issuerKeyHashLength ) );
904
905 REQUIRES( issuerKeyHashLength == KEYID_SIZE );
906 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
907 certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
908 certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
909 REQUIRES( certInfoPtr->issuerDNptr != NULL );
910 REQUIRES( certInfoPtr->cCertCert->serialNumber != NULL );
911
912 /* Get the issuerName hash */
913 getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic,
914 &hashSize );
915 hashFunctionAtomic( hashBuffer, CRYPT_MAX_HASHSIZE,
916 certInfoPtr->issuerDNptr,
917 certInfoPtr->issuerDNsize );
918
919 /* Write the request data */
920 writeSequence( stream,
921 sizeofAlgoID( CRYPT_ALGO_SHA1 ) + \
922 sizeofObject( hashSize ) + sizeofObject( hashSize ) + \
923 sizeofInteger( certInfoPtr->cCertCert->serialNumber,
924 certInfoPtr->cCertCert->serialNumberLength ) );
925 writeAlgoID( stream, CRYPT_ALGO_SHA1 );
926 writeOctetString( stream, hashBuffer, hashSize, DEFAULT_TAG );
927 writeOctetString( stream, issuerKeyHash, issuerKeyHashLength,
928 DEFAULT_TAG );
929 return( writeInteger( stream, certInfoPtr->cCertCert->serialNumber,
930 certInfoPtr->cCertCert->serialNumberLength,
931 DEFAULT_TAG ) );
932 }
933
934 /* Copy revocation information from an OCSP request to a response */
935
936 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyOcspReqToResp(INOUT CERT_INFO * certInfoPtr,INOUT CERT_INFO * ocspRequestInfoPtr)937 static int copyOcspReqToResp( INOUT CERT_INFO *certInfoPtr,
938 INOUT CERT_INFO *ocspRequestInfoPtr )
939 {
940 int status;
941
942 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
943 assert( isWritePtr( ocspRequestInfoPtr, sizeof( CERT_INFO ) ) );
944
945 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
946 REQUIRES( certInfoPtr->cCertRev->revocations == NULL );
947 REQUIRES( ocspRequestInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
948
949 /* Copy the revocation information and extensions */
950 status = copyRevocationEntries( &certInfoPtr->cCertRev->revocations,
951 ocspRequestInfoPtr->cCertRev->revocations );
952 if( cryptStatusOK( status ) )
953 status = copyOCSPRequestAttributes( &certInfoPtr->attributes,
954 ocspRequestInfoPtr->attributes );
955 if( cryptStatusError( status ) )
956 return( status );
957
958 return( CRYPT_OK );
959 }
960
961 /* Copy the certificate information to the revocation list. First we make
962 sure that the CA certificate hash (needed for OCSP's weird certificate
963 ID) is present. We add the necessary information as a pre-encoded blob
964 since we can't do much with the ID fields */
965
966 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyCertToOCSPRequest(INOUT CERT_INFO * ocspRequestInfoPtr,INOUT CERT_INFO * certInfoPtr)967 static int copyCertToOCSPRequest( INOUT CERT_INFO *ocspRequestInfoPtr,
968 INOUT CERT_INFO *certInfoPtr )
969 {
970 CERT_REV_INFO *revInfoPtr = ocspRequestInfoPtr->cCertRev;
971 STREAM stream;
972 DYNBUF essCertDB;
973 BYTE idBuffer[ 256 + 8 ], *idBufPtr = idBuffer;
974 int idLength DUMMY_INIT, status;
975
976 assert( isWritePtr( ocspRequestInfoPtr, sizeof( CERT_INFO ) ) );
977 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
978
979 REQUIRES( ocspRequestInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
980 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
981 certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
982 certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
983
984 /* Make sure that there's a CA certificate hash present */
985 if( !ocspRequestInfoPtr->certHashSet )
986 {
987 setErrorInfo( ocspRequestInfoPtr, CRYPT_CERTINFO_CACERTIFICATE,
988 CRYPT_ERRTYPE_ATTR_ABSENT );
989 return( CRYPT_ERROR_NOTINITED );
990 }
991
992 /* Generate the OCSP certificate ID */
993 sMemNullOpen( &stream );
994 status = writeOCSPID( &stream, certInfoPtr,
995 ocspRequestInfoPtr->certHash, KEYID_SIZE );
996 if( cryptStatusOK( status ) )
997 idLength = stell( &stream );
998 sMemClose( &stream );
999 if( cryptStatusError( status ) )
1000 return( status );
1001 if( idLength > 256 )
1002 {
1003 /* Allocate a buffer for an oversize ID */
1004 if( ( idBufPtr = clDynAlloc( "copyCertToOCSPRequest", \
1005 idLength ) ) == NULL )
1006 return( CRYPT_ERROR_MEMORY );
1007 }
1008 sMemOpen( &stream, idBufPtr, idLength );
1009 status = writeOCSPID( &stream, certInfoPtr,
1010 ocspRequestInfoPtr->certHash, KEYID_SIZE );
1011 sMemDisconnect( &stream );
1012 if( cryptStatusOK( status ) )
1013 {
1014 status = addRevocationEntry( &revInfoPtr->revocations,
1015 &revInfoPtr->currentRevocation,
1016 CRYPT_KEYID_NONE, idBufPtr,
1017 idLength, FALSE );
1018 }
1019 if( idBufPtr != idBuffer )
1020 clFree( "copyCertToOCSPRequest", idBufPtr );
1021 if( status == CRYPT_ERROR_DUPLICATE )
1022 {
1023 /* If this certificate is already present in the list, set the
1024 extended error code for it */
1025 setErrorInfo( ocspRequestInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
1026 CRYPT_ERRTYPE_ATTR_PRESENT );
1027 }
1028 if( cryptStatusError( status ) )
1029 return( status );
1030
1031 /* Add the certificate information again as an ESSCertID extension to
1032 work around the problems inherent in OCSP IDs */
1033 status = dynCreate( &essCertDB, certInfoPtr->objectHandle,
1034 CRYPT_IATTRIBUTE_ESSCERTID );
1035 if( cryptStatusOK( status ) )
1036 {
1037 CRYPT_ATTRIBUTE_TYPE dummy1;
1038 CRYPT_ERRTYPE_TYPE dummy2;
1039
1040 /* Since this isn't a critical extension (the ESSCertID is just a
1041 backup for the main, albeit not very useful, ID) we continue if
1042 there's a problem adding it */
1043 ( void ) addAttributeFieldString( \
1044 &revInfoPtr->currentRevocation->attributes,
1045 CRYPT_CERTINFO_CMS_SIGNINGCERT_ESSCERTID,
1046 CRYPT_ATTRIBUTE_NONE, dynData( essCertDB ),
1047 dynLength( essCertDB ), ATTR_FLAG_NONE,
1048 &dummy1, &dummy2 );
1049 dynDestroy( &essCertDB );
1050 }
1051 return( CRYPT_OK );
1052 }
1053
1054 /* Get the hash of the public key (for an OCSP request), possibly
1055 overwriting a previous hash if there are multiple entries in the
1056 request */
1057
1058 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyCaCertToOCSPReq(INOUT CERT_INFO * certInfoPtr,INOUT CERT_INFO * caCertInfoPtr)1059 static int copyCaCertToOCSPReq( INOUT CERT_INFO *certInfoPtr,
1060 INOUT CERT_INFO *caCertInfoPtr )
1061 {
1062 HASH_FUNCTION_ATOMIC hashFunctionAtomic;
1063 STREAM stream;
1064 void *dataPtr DUMMY_INIT_PTR;
1065 int length, status;
1066
1067 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1068 assert( isWritePtr( caCertInfoPtr, sizeof( CERT_INFO ) ) );
1069
1070 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
1071 REQUIRES( caCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
1072 caCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
1073 REQUIRES( caCertInfoPtr->publicKeyInfo != NULL );
1074
1075 getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic, NULL );
1076
1077 /* Dig down into the encoded key data to find the weird bits of key that
1078 OCSP requires us to hash. We store the result as the certificate
1079 hash, this is safe because this value isn't used for an OCSP request
1080 so it can't be accessed externally */
1081 sMemConnect( &stream, caCertInfoPtr->publicKeyInfo,
1082 caCertInfoPtr->publicKeyInfoSize );
1083 readSequence( &stream, NULL ); /* Wrapper */
1084 readUniversal( &stream ); /* AlgoID */
1085 status = readBitStringHole( &stream, &length, 16, DEFAULT_TAG );
1086 if( cryptStatusOK( status ) ) /* BIT STRING wrapper */
1087 status = sMemGetDataBlock( &stream, &dataPtr, length );
1088 if( cryptStatusError( status ) )
1089 {
1090 /* There's a problem with the format of the key */
1091 DEBUG_DIAG(( "Invalid certificate data format when hashing "
1092 "certificate to create OCSP ID" ));
1093 assert( DEBUG_WARN );
1094 sMemDisconnect( &stream );
1095 setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CACERTIFICATE,
1096 CRYPT_ERRTYPE_ATTR_VALUE );
1097 return( CRYPT_ERROR_INVALID );
1098 }
1099 hashFunctionAtomic( certInfoPtr->certHash, KEYID_SIZE, dataPtr, length );
1100 certInfoPtr->certHashSet = TRUE;
1101 sMemDisconnect( &stream );
1102
1103 return( CRYPT_OK );
1104 }
1105 #endif /* USE_CERTREV */
1106
1107 /****************************************************************************
1108 * *
1109 * Copy Certificate Validation Data *
1110 * *
1111 ****************************************************************************/
1112
1113 #ifdef USE_CERTVAL
1114
1115 /* Copy validity information from an RTCS request to a response */
1116
1117 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyRtcsReqToResp(INOUT CERT_INFO * certInfoPtr,INOUT CERT_INFO * rtcsRequestInfoPtr)1118 static int copyRtcsReqToResp( INOUT CERT_INFO *certInfoPtr,
1119 INOUT CERT_INFO *rtcsRequestInfoPtr )
1120 {
1121 int status;
1122
1123 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1124 assert( isWritePtr( rtcsRequestInfoPtr, sizeof( CERT_INFO ) ) );
1125
1126 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE );
1127 REQUIRES( certInfoPtr->cCertVal->validityInfo == NULL );
1128 REQUIRES( rtcsRequestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST );
1129
1130 /* Copy the certificate validity information and extensions */
1131 status = copyValidityEntries( &certInfoPtr->cCertVal->validityInfo,
1132 rtcsRequestInfoPtr->cCertVal->validityInfo );
1133 if( cryptStatusOK( status ) )
1134 status = copyRTCSRequestAttributes( &certInfoPtr->attributes,
1135 rtcsRequestInfoPtr->attributes );
1136 return( status );
1137 }
1138
1139 /* Copy the certificate hash. We read the value indirectly since it's
1140 computed on demand and may not have been evaluated yet */
1141
1142 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyCertToRTCSRequest(INOUT CERT_INFO * rtcsRequestInfoPtr,INOUT CERT_INFO * certInfoPtr)1143 static int copyCertToRTCSRequest( INOUT CERT_INFO *rtcsRequestInfoPtr,
1144 INOUT CERT_INFO *certInfoPtr )
1145 {
1146 CERT_VAL_INFO *valInfoPtr = rtcsRequestInfoPtr->cCertVal;
1147 BYTE certHash[ CRYPT_MAX_HASHSIZE + 8 ];
1148 int certHashLength, status;
1149
1150 assert( isWritePtr( rtcsRequestInfoPtr, sizeof( CERT_INFO ) ) );
1151 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1152
1153 REQUIRES( rtcsRequestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST );
1154 REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
1155 certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
1156 certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
1157
1158 status = getCertComponentString( certInfoPtr,
1159 CRYPT_CERTINFO_FINGERPRINT_SHA1,
1160 certHash, CRYPT_MAX_HASHSIZE,
1161 &certHashLength );
1162 if( cryptStatusOK( status ) )
1163 {
1164 status = addValidityEntry( &valInfoPtr->validityInfo,
1165 &valInfoPtr->currentValidity,
1166 certHash, certHashLength );
1167 }
1168 if( status == CRYPT_ERROR_DUPLICATE )
1169 {
1170 /* If this certificate is already present in the list, set the
1171 extended error code for it */
1172 setErrorInfo( rtcsRequestInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
1173 CRYPT_ERRTYPE_ATTR_PRESENT );
1174 }
1175 return( status );
1176 }
1177 #endif /* USE_CERTVAL */
1178
1179 /****************************************************************************
1180 * *
1181 * Certificate Information Copy External Interface *
1182 * *
1183 ****************************************************************************/
1184
1185 /* Copy user certificate information into a certificate object, either a
1186 CRL, a certification/revocation request, or an RTCS/OCSP request */
1187
1188 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyUserCertInfo(INOUT CERT_INFO * certInfoPtr,INOUT CERT_INFO * userCertInfoPtr,IN_HANDLE const CRYPT_HANDLE iCryptHandle)1189 static int copyUserCertInfo( INOUT CERT_INFO *certInfoPtr,
1190 INOUT CERT_INFO *userCertInfoPtr,
1191 IN_HANDLE const CRYPT_HANDLE iCryptHandle )
1192 {
1193 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1194 assert( isWritePtr( userCertInfoPtr, sizeof( CERT_INFO ) ) );
1195
1196 REQUIRES( isHandleRangeValid( iCryptHandle ) );
1197 REQUIRES( userCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
1198 userCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
1199 REQUIRES( userCertInfoPtr->certificate != NULL );
1200
1201 /* If it's an RTCS or OCSP request, remember the responder URL if there's
1202 one present. We can't leave it to be read out of the certificate
1203 because authorityInfoAccess isn't a valid attribute for RTCS/OCSP
1204 requests */
1205 #ifdef USE_CERTREV
1206 if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST && \
1207 certInfoPtr->cCertRev->responderUrl == NULL )
1208 {
1209 int status;
1210
1211 status = copyResponderURL( certInfoPtr, userCertInfoPtr );
1212 if( cryptStatusError( status ) )
1213 return( status );
1214 }
1215 #endif /* USE_CERTREV */
1216 #ifdef USE_CERTVAL
1217 if( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST && \
1218 certInfoPtr->cCertVal->responderUrl == NULL )
1219 {
1220 int status;
1221
1222 status = copyResponderURL( certInfoPtr, userCertInfoPtr );
1223 if( cryptStatusError( status ) )
1224 return( status );
1225 }
1226 #endif /* USE_CERTVAL */
1227
1228 /* Copy the required information across to the certificate */
1229 switch( certInfoPtr->type )
1230 {
1231 #ifdef USE_CERTREQ
1232 case CRYPT_CERTTYPE_REQUEST_CERT:
1233 return( copyCertToRequest( certInfoPtr, userCertInfoPtr,
1234 iCryptHandle ) );
1235
1236 case CRYPT_CERTTYPE_REQUEST_REVOCATION:
1237 return( copyCertToRevRequest( certInfoPtr, userCertInfoPtr ) );
1238 #endif /* USE_CERTREQ */
1239
1240 #ifdef USE_CERTREV
1241 case CRYPT_CERTTYPE_CRL:
1242 return( copyRevocationInfo( certInfoPtr, userCertInfoPtr ) );
1243
1244 case CRYPT_CERTTYPE_OCSP_REQUEST:
1245 return( copyCertToOCSPRequest( certInfoPtr, userCertInfoPtr ) );
1246 #endif /* USE_CERTREV */
1247
1248 #ifdef USE_CERTVAL
1249 case CRYPT_CERTTYPE_RTCS_REQUEST:
1250 return( copyCertToRTCSRequest( certInfoPtr, userCertInfoPtr ) );
1251 #endif /* USE_CERTVAL */
1252 }
1253
1254 retIntError();
1255 }
1256
1257 /* A general dispatch function for copying information from one certificate
1258 object to another. This is a wrapper that acquires the source object's
1259 data and then passes a pointer to it to the actual copy function that
1260 copies any necessary information to the destination object, releasing the
1261 source object after the copy */
1262
1263 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
copyCertObject(INOUT CERT_INFO * certInfoPtr,IN_HANDLE const CRYPT_CERTIFICATE addedCert,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,IN const int certInfo)1264 int copyCertObject( INOUT CERT_INFO *certInfoPtr,
1265 IN_HANDLE const CRYPT_CERTIFICATE addedCert,
1266 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
1267 IN const int certInfo )
1268 {
1269 CERT_INFO *addedCertInfoPtr;
1270 int status;
1271
1272 assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1273
1274 REQUIRES( isAttribute( certInfoType ) || \
1275 isInternalAttribute( certInfoType ) );
1276 REQUIRES( isHandleRangeValid( addedCert ) );
1277
1278 status = krnlAcquireObject( addedCert, OBJECT_TYPE_CERTIFICATE,
1279 ( void ** ) &addedCertInfoPtr,
1280 CRYPT_ARGERROR_NUM1 );
1281 if( cryptStatusError( status ) )
1282 return( status );
1283 ANALYSER_HINT( addedCertInfoPtr != NULL );
1284 switch( certInfoType )
1285 {
1286 case CRYPT_CERTINFO_CERTIFICATE:
1287 status = copyUserCertInfo( certInfoPtr, addedCertInfoPtr,
1288 certInfo );
1289 break;
1290
1291 #ifdef USE_CERTREV
1292 case CRYPT_CERTINFO_CACERTIFICATE:
1293 status = copyCaCertToOCSPReq( certInfoPtr, addedCertInfoPtr );
1294 break;
1295 #endif /* USE_CERTREV */
1296
1297 #ifdef USE_CERTREQ
1298 case CRYPT_CERTINFO_CERTREQUEST:
1299 status = copyCertReqToCert( certInfoPtr, addedCertInfoPtr );
1300 break;
1301 #endif /* USE_CERTREQ */
1302
1303 #ifdef USE_CERTVAL
1304 case CRYPT_IATTRIBUTE_RTCSREQUEST:
1305 status = copyRtcsReqToResp( certInfoPtr, addedCertInfoPtr );
1306 break;
1307 #endif /* USE_CERTVAL */
1308
1309 #ifdef USE_CERTREV
1310 case CRYPT_IATTRIBUTE_OCSPREQUEST:
1311 status = copyOcspReqToResp( certInfoPtr, addedCertInfoPtr );
1312 break;
1313
1314 case CRYPT_IATTRIBUTE_REVREQUEST:
1315 status = copyRevReqToCert( certInfoPtr, addedCertInfoPtr );
1316 break;
1317 #endif /* USE_CERTREV */
1318
1319 #ifdef USE_PKIUSER
1320 case CRYPT_IATTRIBUTE_PKIUSERINFO:
1321 status = copyPkiUserToCertReq( certInfoPtr, addedCertInfoPtr );
1322 break;
1323 #endif /* USE_PKIUSER */
1324
1325 #ifdef USE_DBMS /* Only used by CA code */
1326 case CRYPT_IATTRIBUTE_BLOCKEDATTRS:
1327 status = sanitiseCertAttributes( certInfoPtr,
1328 addedCertInfoPtr->attributes );
1329 break;
1330 #endif /* USE_DBMS */
1331
1332 default:
1333 retIntError();
1334 }
1335 krnlReleaseObject( addedCertInfoPtr->objectHandle );
1336 return( status );
1337 }
1338 #endif /* USE_CERTIFICATES */
1339