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