1 /****************************************************************************
2 *																			*
3 *					Certificate Write Preparation Routines					*
4 *						Copyright Peter Gutmann 1996-2008					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "cert.h"
10   #include "asn1_ext.h"
11 #else
12   #include "cert/cert.h"
13   #include "enc_dec/asn1_ext.h"
14 #endif /* Compiler-specific includes */
15 
16 /* Before we encode a certificate object we have to perform various final
17    setup actions and check that the object is ready for encoding.  The setup
18    operations and checks for the different object types are:
19 
20 				|  Cert	|  Attr	|  P10	|Cr.Req	|Rv.Req
21 	------------+-------+-------+-------+-------+-------+
22 	STDATTR		|	X[1]|		|		|		|		| Setup
23 	ISSUERATTR	|	X	|	X	|		|		|		| action
24 	ISSUERDN	|	X	|	X	|		|		|		|
25 	VALPERIOD	|	X	|	X	|		|		|		|
26 	VALINFO		|		|		|		|		|		|
27 	REVINFO		|		|		|		|		|		|
28 	------------+-------+-------+-------+-------+-------+
29 	SPKI		|	X	|		|	X	|	X	|		| Check
30 	DN			|	X	|	X	|		|		|		|
31 	DN_PART		|		|		|	X	|	X	|		|
32 	ISSUERDN	|	X	|	X	|		|		|	X	|
33 	ISSUERCRTDN	|		|		|		|		|		|
34 	NON_SELFSD	|	X	|	X	|		|		|		|
35 	SERIALNO	|	X	|	X	|		|		|	X	|
36 	REVENTRIES	|		|		|		|		|		|
37 	------------+-------+-------+-------+-------+-------+
38 
39 				|RTCS Rq|RTCS Rs|OCSP Rq|OCSP Rs|  CRL	|CRLentr|
40 	------------+-------+-------+-------+-------+-------+-------+
41 	STDATTR		|		|		|		|		|		|		| Setup
42 	ISSUERATTR	|		|		|		|		|	X	|		| action
43 	ISSUERDN	|		|		|		|		|	X	|		|
44 	VALPERIOD	|		|		|		|		|		|		|
45 	VALINFO		|	X	|		|		|		|		|		|
46 	REVINFO		|		|		|	X	|		|	X	|	X	|
47 	------------+-------+-------+-------+-------+-------+-------+
48 	SPKI		|		|		|		|		|		|		| Check
49 	DN			|		|		|		|	X	|		|		|
50 	DN_PART		|		|		|		|		|		|		|
51 	ISSUERDN	|		|		|		|		|	X	|		|
52 	ISSUERCRTDN	|		|		|		|		|	X	|		|
53 	NON_SELFSD	|		|		|		|		|		|		|
54 	SERIALNO	|		|		|		|		|		|		|
55 	VALENTRIES	|	X	|		|		|		|		|		|
56 	REVENTRIES	|		|		|	X	|	X	|		|		|
57 	------------+-------+-------+-------+-------+-------+-------+
58 
59    We have to be careful here to avoid race conditions when some of the
60    checks depend on setup actions having been performed first but some of
61    the setup actions require that checks be performed first.  The noted
62    exceptions are:
63 
64 	[1] Requires that the SPKI check be performed first since STDATTR
65 		evaluates keyUsage from the SPKI */
66 
67 #ifdef USE_CERTIFICATES
68 
69 /****************************************************************************
70 *																			*
71 *								Utility Functions							*
72 *																			*
73 ****************************************************************************/
74 
75 /* Add standard X.509v3 extensions to a certificate if they're not already
76    present.  This function simply adds the required extensions, it doesn't
77    check for consistency with existing extensions which is done later by
78    checkAttributes() and checkCert() */
79 
80 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
addStandardExtensions(INOUT CERT_INFO * certInfoPtr)81 static int addStandardExtensions( INOUT CERT_INFO *certInfoPtr )
82 	{
83 	BOOLEAN isCA = FALSE;
84 	int keyUsage, extKeyUsage, value, status;
85 
86 	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
87 
88 	/* Get the implicit keyUsage flags (based on any extended key usage
89 	   extensions present) and explicit key usage flags, which we use to
90 	   extend the basic keyUsage flags if required */
91 	status = getKeyUsageFromExtKeyUsage( certInfoPtr, &extKeyUsage,
92 						&certInfoPtr->errorLocus, &certInfoPtr->errorType );
93 	if( cryptStatusError( status ) )
94 		return( status );
95 	status = getAttributeFieldValue( certInfoPtr->attributes,
96 									 CRYPT_CERTINFO_KEYUSAGE,
97 									 CRYPT_ATTRIBUTE_NONE, &keyUsage );
98 	if( cryptStatusError( status ) )
99 		{
100 		if( status != CRYPT_ERROR_NOTFOUND )
101 			return( status );
102 
103 		/* There's no keyUsage attribute present, mark the value as being
104 		   not set so that we explicitly set it later */
105 		keyUsage = CRYPT_ERROR;
106 		}
107 
108 	/* If there's an explicit key usage present, make sure that it's
109 	   consistent with the implicit key usage flags derived from the
110 	   extended key usage.  We mask out the nonRepudiation bit for reasons
111 	   given in chk_cert.c.
112 
113 	   This check is also performed by checkCert(), however we need to
114 	   explicitly perform it here as well since we need to add a key usage
115 	   to match the extKeyUsage before calling checkCert() if one wasn't
116 	   explicitly set or checkCert() will reject the certificate because of
117 	   the inconsistent keyUsage */
118 	if( keyUsage > 0 )
119 		{
120 		const int effectiveKeyUsage = \
121 						extKeyUsage & ~CRYPT_KEYUSAGE_NONREPUDIATION;
122 
123 		if( ( keyUsage & effectiveKeyUsage ) != effectiveKeyUsage )
124 			{
125 			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
126 						  CRYPT_ERRTYPE_CONSTRAINT );
127 			return( CRYPT_ERROR_INVALID );
128 			}
129 		}
130 
131 	/* Check whether this is a CA certificate.  If there's no
132 	   basicConstraints attribute present, add one and make it a non-CA
133 	   certificate */
134 	status = getAttributeFieldValue( certInfoPtr->attributes,
135 									 CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE,
136 									 &value );
137 	if( cryptStatusOK( status ) )
138 		isCA = ( value > 0 ) ? TRUE : FALSE;
139 	else
140 		{
141 		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_CA, FALSE );
142 		if( cryptStatusError( status ) )
143 			return( status );
144 		}
145 
146 	/* If there's no explicit keyUsage information present add it based on
147 	   various implicit information.  We also add key feature information
148 	   which is used to help automate key management, for example to inhibit
149 	   speculative reads of keys held in removable tokens, which can result
150 	   in spurious insert-token dialogs being presented to the user outside
151 	   the control of cryptlib if the token isn't present */
152 	if( keyUsage <= 0 )
153 		{
154 		/* If there's no implicit key usage present and it's not a CA (for
155 		   which we don't want to set things like encryption flags for the
156 		   CA certificate), set the key usage flags based on the
157 		   capabilities of the associated context.  Because no-one can
158 		   figure out what the nonRepudiation flag signifies we don't set
159 		   this, if the user wants it they have to specify it explicitly.
160 		   Similarly we don't try and set the keyAgreement encipher/decipher-
161 		   only flags, which were tacked on as variants of keyAgreement long
162 		   after the basic keyAgreement flag was defined */
163 		if( extKeyUsage <= 0 && !isCA )
164 			{
165 			keyUsage = 0;	/* Reset key usage */
166 			if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
167 				{
168 				/* There's a context present, check its capabilities.  This
169 				   has the advantage that it takes into account any ACLs
170 				   that may exist for the key */
171 				if( cryptStatusOK( \
172 						krnlSendMessage( certInfoPtr->iPubkeyContext,
173 										 IMESSAGE_CHECK, NULL,
174 										 MESSAGE_CHECK_PKC_SIGCHECK ) ) )
175 					keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
176 				if( cryptStatusOK( \
177 						krnlSendMessage( certInfoPtr->iPubkeyContext,
178 										 IMESSAGE_CHECK, NULL,
179 										 MESSAGE_CHECK_PKC_ENCRYPT ) ) )
180 					keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
181 				if( cryptStatusOK( \
182 						krnlSendMessage( certInfoPtr->iPubkeyContext,
183 										 IMESSAGE_CHECK, NULL,
184 										 MESSAGE_CHECK_PKC_KA_EXPORT ) ) || \
185 					cryptStatusOK( \
186 						krnlSendMessage( certInfoPtr->iPubkeyContext,
187 										 IMESSAGE_CHECK, NULL,
188 										 MESSAGE_CHECK_PKC_KA_IMPORT ) ) )
189 					keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
190 				}
191 			else
192 				{
193 				/* There's no context present (the key is present as encoded
194 				   data), assume we can do whatever the algorithm allows */
195 				if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
196 					keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
197 				if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
198 					keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
199 				if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
200 					keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
201 				}
202 			}
203 		else
204 			{
205 			/* There's an extended key usage set but no basic keyUsage, make
206 			   the keyUsage consistent with the usage flags derived from the
207 			   extended usage */
208 			keyUsage = extKeyUsage;
209 
210 			/* If it's a CA key, make sure that it's a signing key and
211 			   enable its use for certification-related purposes*/
212 			if( isCA )
213 				{
214 				BOOLEAN usageOK;
215 
216 				if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
217 					{
218 					usageOK = cryptStatusOK( \
219 								krnlSendMessage( certInfoPtr->iPubkeyContext,
220 												 IMESSAGE_CHECK, NULL,
221 												 MESSAGE_CHECK_PKC_SIGCHECK ) );
222 					}
223 				else
224 					usageOK = isSigAlgo( certInfoPtr->publicKeyAlgo );
225 				if( !usageOK )
226 					{
227 					setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CA,
228 								  CRYPT_ERRTYPE_CONSTRAINT );
229 					return( CRYPT_ERROR_INVALID );
230 					}
231 				keyUsage |= KEYUSAGE_CA;
232 				}
233 			}
234 		ENSURES( keyUsage > CRYPT_KEYUSAGE_NONE && \
235 				 keyUsage < CRYPT_KEYUSAGE_LAST );
236 		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
237 								   keyUsage );
238 		if( cryptStatusError( status ) )
239 			return( status );
240 		}
241 	if( certInfoPtr->publicKeyFeatures > 0 )
242 		{
243 		/* This is a bitstring so we only add it if there are feature flags
244 		   present to avoid writing zero-length values */
245 		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYFEATURES,
246 								   certInfoPtr->publicKeyFeatures );
247 		if( cryptStatusError( status ) && status != CRYPT_ERROR_INITED )
248 			return( status );
249 		}
250 
251 	/* Add the subjectKeyIdentifier */
252 #if 0	/* 10/12/12 To test situations where keyID != sKID, enable the
253 					following code */
254 {
255 BYTE buffer[ 128 ];
256 
257 memcpy( buffer, certInfoPtr->publicKeyID, KEYID_SIZE );
258 memset( buffer, 0xFF, KEYID_SIZE / 2 );
259 return( addCertComponentString( certInfoPtr,
260 								CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
261 								buffer, KEYID_SIZE ) );
262 }
263 #endif /* 0 */
264 	return( addCertComponentString( certInfoPtr,
265 									CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
266 									certInfoPtr->publicKeyID, KEYID_SIZE ) );
267 	}
268 
269 /****************************************************************************
270 *																			*
271 *							Pre-encode Checking Functions					*
272 *																			*
273 ****************************************************************************/
274 
275 /* Check whether an empty DN is permitted in a certificate.  This is a PKIX
276    peculiarity that causes severe problems for virtually all certificate-
277    using protocols so we only allow it at a compliance level of
278    CRYPT_COMPLIANCELEVEL_PKIX_FULL */
279 
280 #ifdef USE_CERTLEVEL_PKIX_FULL
281 
282 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
checkEmptyDnOK(INOUT CERT_INFO * subjectCertInfoPtr)283 static BOOLEAN checkEmptyDnOK( INOUT CERT_INFO *subjectCertInfoPtr )
284 	{
285 	ATTRIBUTE_PTR *attributePtr;
286 	int value, complianceLevel, status;
287 
288 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
289 
290 	/* PKIX allows empty subject DNs if a subject altName is present,
291 	   however creating certificates like this breaks every certificate-
292 	   using protocol supported by cryptlib so we only allow it at the
293 	   highest compliance level */
294 	if( cryptStatusError( \
295 			krnlSendMessage( subjectCertInfoPtr->ownerHandle,
296 							 IMESSAGE_GETATTRIBUTE, &complianceLevel,
297 							 CRYPT_OPTION_CERT_COMPLIANCELEVEL ) ) || \
298 		complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_FULL )
299 		{
300 		/* We only allow this behaviour at the highest compliance level */
301 		return( FALSE );
302 		}
303 
304 	/* We also have to be very careful to ensure that the empty subject
305 	   DN can't end up becoming an empty issuer DN, which can occur if it's
306 	   a self-signed certificate */
307 	if( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED )
308 		{
309 		/* We can't have an empty issuer (== subject) DN */
310 		return( FALSE );
311 		}
312 
313 	/* In addition if it's a CA certificate then the subject DN can't be
314 	   empty, for obvious reasons */
315 	status = getAttributeFieldValue( subjectCertInfoPtr->attributes,
316 									 CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE,
317 									 &value );
318 	if( cryptStatusOK( status ) && value > 0 )
319 		{
320 		/* It's a CA certificate, the subject DN can't be empty */
321 		return( FALSE );
322 		}
323 
324 	/* Finally, if there's no subject DN present then there has to be an
325 	   altName present to take its place */
326 	attributePtr = findAttributeField( subjectCertInfoPtr->attributes,
327 									   CRYPT_CERTINFO_SUBJECTALTNAME,
328 									   CRYPT_ATTRIBUTE_NONE );
329 	if( attributePtr == NULL )
330 		{
331 		/* Either a subject DN or subject altName must be present */
332 		return( FALSE );
333 		}
334 
335 	/* There's a subject altName present but no subject DN, mark the altName
336 	   as critical */
337 	setAttributeProperty( attributePtr, ATTRIBUTE_PROPERTY_CRITICAL, 0 );
338 
339 	return( TRUE );
340 	}
341 #endif /* USE_CERTLEVEL_PKIX_FULL */
342 
343 /* Perform any final setup actions that add default and issuer-contributed
344    attributes */
345 
346 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
preEncodeCertificate(INOUT CERT_INFO * subjectCertInfoPtr,IN_OPT const CERT_INFO * issuerCertInfoPtr,IN_FLAGS (PRE_SET)const int actions)347 int preEncodeCertificate( INOUT CERT_INFO *subjectCertInfoPtr,
348 						  IN_OPT const CERT_INFO *issuerCertInfoPtr,
349 						  IN_FLAGS( PRE_SET ) const int actions )
350 	{
351 	int status;
352 
353 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
354 	assert( ( issuerCertInfoPtr == NULL ) || \
355 			isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
356 
357 	REQUIRES( actions >= PRE_SET_NONE && \
358 			  actions <= PRE_SET_FLAG_MAX );
359 	REQUIRES( ( ( actions & ( PRE_SET_ISSUERATTR | PRE_SET_ISSUERDN | \
360 							  PRE_SET_VALIDITYPERIOD ) ) && \
361 				issuerCertInfoPtr != NULL ) || \
362 			  !( actions & ( PRE_SET_ISSUERATTR | PRE_SET_ISSUERDN | \
363 							 PRE_SET_VALIDITYPERIOD ) ) );
364 
365 	/* If it's a >= v3 certificate add the standard X.509v3 extensions if
366 	   these aren't already present */
367 	if( actions & PRE_SET_STANDARDATTR )
368 		{
369 		/* Setting the standard attributes requires the presence of a public
370 		   key to get keyUsage information from, so we have to check this
371 		   before we can add any attributes.  This would normally be checked
372 		   as part of the range of checking performedin
373 		   preCheckCertificate(), but that isn't called until the pre-
374 		   encoding functions here have been performed */
375 		if( subjectCertInfoPtr->publicKeyInfo == NULL )
376 			{
377 			setErrorInfo( subjectCertInfoPtr,
378 						  CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
379 						  CRYPT_ERRTYPE_ATTR_ABSENT );
380 			return( CRYPT_ERROR_NOTINITED );
381 			}
382 
383 		/* Attributes are only allowed with version 3 certificates */
384 		if( subjectCertInfoPtr->version >= X509_V3 )
385 			{
386 			status = addStandardExtensions( subjectCertInfoPtr );
387 			if( cryptStatusError( status ) )
388 				return( status );
389 			}
390 		}
391 
392 	/* Copy any required extensions from the issuer to the subject
393 	   certificate if necessary */
394 	if( actions & PRE_SET_ISSUERATTR )
395 		{
396 		ANALYSER_HINT( issuerCertInfoPtr != NULL );
397 
398 		if( !( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
399 			{
400 			status = copyIssuerAttributes( &subjectCertInfoPtr->attributes,
401 										   issuerCertInfoPtr->attributes,
402 										   subjectCertInfoPtr->type,
403 										   &subjectCertInfoPtr->errorLocus,
404 										   &subjectCertInfoPtr->errorType );
405 			if( cryptStatusError( status ) )
406 				return( status );
407 			}
408 		}
409 
410 	/* Copy the issuer DN if this isn't already present */
411 	if( actions & PRE_SET_ISSUERDN )
412 		{
413 		ANALYSER_HINT( issuerCertInfoPtr != NULL );
414 
415 		if( subjectCertInfoPtr->issuerName == NULL )
416 			{
417 			status = copyDN( &subjectCertInfoPtr->issuerName,
418 							 issuerCertInfoPtr->subjectName );
419 			if( cryptStatusError( status ) )
420 				return( status );
421 			}
422 		}
423 
424 	/* Constrain the subject validity period to be within the issuer
425 	   validity period */
426 	if( actions & PRE_SET_VALIDITYPERIOD )
427 		{
428 		ANALYSER_HINT( issuerCertInfoPtr != NULL );
429 
430 		if( subjectCertInfoPtr->startTime < issuerCertInfoPtr->startTime )
431 			subjectCertInfoPtr->startTime = issuerCertInfoPtr->startTime;
432 		if( subjectCertInfoPtr->endTime > issuerCertInfoPtr->endTime )
433 			subjectCertInfoPtr->endTime = issuerCertInfoPtr->endTime;
434 		}
435 
436 #ifdef USE_CERTVAL
437 	/* If it's an RTCS response, prepare the certificate status list entries
438 	   prior to encoding them */
439 	if( actions & PRE_SET_VALINFO )
440 		{
441 		status = prepareValidityEntries( subjectCertInfoPtr->cCertVal->validityInfo,
442 										 &subjectCertInfoPtr->cCertVal->currentValidity,
443 										 &subjectCertInfoPtr->errorLocus,
444 										 &subjectCertInfoPtr->errorType );
445 		if( cryptStatusError( status ) )
446 			return( status );
447 		}
448 #endif /* USE_CERTVAL */
449 
450 #ifdef USE_CERTREV
451 	/* If it's a CRL or OCSP response, prepare the revocation list entries
452 	   prior to encoding them */
453 	if( actions & PRE_SET_REVINFO )
454 		{
455 		REVOCATION_INFO *revocationErrorEntry;
456 		const BOOLEAN isCrlEntry = \
457 						( ( subjectCertInfoPtr->type == CRYPT_CERTTYPE_CRL ) && \
458 						  !( actions & PRE_SET_ISSUERDN ) ) ? TRUE : FALSE;
459 
460 		status = prepareRevocationEntries( subjectCertInfoPtr->cCertRev->revocations,
461 										   subjectCertInfoPtr->cCertRev->revocationTime,
462 										   &revocationErrorEntry, isCrlEntry,
463 										   &subjectCertInfoPtr->errorLocus,
464 										   &subjectCertInfoPtr->errorType );
465 		if( cryptStatusError( status ) )
466 			{
467 			/* If there was an error and we're processing an entire
468 			   revocation list, select the entry that caused the problem */
469 			if( !isCrlEntry )
470 				{
471 				subjectCertInfoPtr->cCertRev->currentRevocation = \
472 													revocationErrorEntry;
473 				}
474 			return( status );
475 			}
476 		}
477 #endif /* USE_CERTREV */
478 
479 	return( CRYPT_OK );
480 	}
481 
482 /* Check that a certificate object is reading for encoding */
483 
484 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
preCheckCertificate(INOUT CERT_INFO * subjectCertInfoPtr,IN_OPT const CERT_INFO * issuerCertInfoPtr,IN_FLAGS (PRE_CHECK)const int actions,IN_FLAGS_Z (PRE)const int flags)485 int preCheckCertificate( INOUT CERT_INFO *subjectCertInfoPtr,
486 						 IN_OPT const CERT_INFO *issuerCertInfoPtr,
487 						 IN_FLAGS( PRE_CHECK ) const int actions,
488 						 IN_FLAGS_Z( PRE ) const int flags )
489 	{
490 	int status;
491 
492 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
493 	assert( ( issuerCertInfoPtr == NULL ) || \
494 			isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
495 
496 	REQUIRES( actions >= PRE_CHECK_NONE && \
497 			  actions <= PRE_CHECK_FLAG_MAX );
498 	REQUIRES( flags == PRE_FLAG_NONE || \
499 			  flags == PRE_FLAG_DN_IN_ISSUERCERT );
500 	REQUIRES( ( ( actions & ( PRE_CHECK_ISSUERCERTDN | \
501 							  PRE_CHECK_NONSELFSIGNED_DN ) ) && \
502 				issuerCertInfoPtr != NULL ) || \
503 			  !( actions & ( PRE_CHECK_ISSUERCERTDN | \
504 							 PRE_CHECK_NONSELFSIGNED_DN ) ) );
505 			  /* We can't impose a complete set of preconditions on the
506 			     issuer certificate because some issuer attributes like the
507 				 issuer DN may already be present in the subject
508 				 certificate */
509 
510 	/* Make sure that there's public-key information present */
511 	if( actions & PRE_CHECK_SPKI )
512 		{
513 		if( subjectCertInfoPtr->publicKeyInfo == NULL )
514 			{
515 			setErrorInfo( subjectCertInfoPtr,
516 						  CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
517 						  CRYPT_ERRTYPE_ATTR_ABSENT );
518 			return( CRYPT_ERROR_NOTINITED );
519 			}
520 		}
521 
522 	/* Make sure that there's a full DN present */
523 	if( actions & PRE_CHECK_DN )
524 		{
525 		status = checkDN( subjectCertInfoPtr->subjectName,
526 						  CHECKDN_FLAG_COUNTRY | CHECKDN_FLAG_COMMONNAME,
527 						  &subjectCertInfoPtr->errorLocus,
528 						  &subjectCertInfoPtr->errorType );
529 		if( cryptStatusError( status ) )
530 			{
531 #ifdef USE_CERTLEVEL_PKIX_FULL
532 			/* In some very special cases an empty DN is permitted so we
533 			   only return an error if this really isn't allowed */
534 			if( status != CRYPT_ERROR_NOTINITED || \
535 				!checkEmptyDnOK( subjectCertInfoPtr ) )
536 #endif /* USE_CERTLEVEL_PKIX_FULL */
537 				return( status );
538 			}
539 		}
540 
541 	/* Make sure that there's at least a partial DN present (some CA's will
542 	   fill the upper portion of the DN themselves so at a minimum all that
543 	   we really need is a CommonName) */
544 	if( actions & PRE_CHECK_DN_PARTIAL )
545 		{
546 		status = checkDN( subjectCertInfoPtr->subjectName,
547 						  CHECKDN_FLAG_COMMONNAME,
548 						  &subjectCertInfoPtr->errorLocus,
549 						  &subjectCertInfoPtr->errorType );
550 		if( cryptStatusError( status ) )
551 			return( status );
552 		}
553 
554 	/* Make sure that there's an issuer DN present */
555 	if( actions & PRE_CHECK_ISSUERDN )
556 		{
557 		if( flags & PRE_FLAG_DN_IN_ISSUERCERT )
558 			{
559 			if( issuerCertInfoPtr == NULL || \
560 				issuerCertInfoPtr->subjectDNptr == NULL || \
561 				issuerCertInfoPtr->subjectDNsize < 1 )
562 				{
563 				setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
564 							  CRYPT_ERRTYPE_ATTR_ABSENT );
565 				return( CRYPT_ERROR_NOTINITED );
566 				}
567 			}
568 		else
569 			{
570 			/* The issuer DN can be present either in pre-encoded form (if
571 			   it was copied from an issuer certificate) or as a full DN (if
572 			   it's a self-signed certificate), so we check for the presence
573 			   of either */
574 			if( ( subjectCertInfoPtr->issuerName == NULL ) &&
575 				( subjectCertInfoPtr->issuerDNptr == NULL || \
576 				  subjectCertInfoPtr->issuerDNsize < 1 ) )
577 				{
578 				setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
579 							  CRYPT_ERRTYPE_ATTR_ABSENT );
580 				return( CRYPT_ERROR_NOTINITED );
581 				}
582 			}
583 		}
584 
585 	/* If it's a CRL, compare the revoked certificate issuer DN and signer
586 	   DN to make sure that we're not trying to revoke someone else's
587 	   certificates, and prepare the revocation entries */
588 	if( actions & PRE_CHECK_ISSUERCERTDN )
589 		{
590 		ANALYSER_HINT( issuerCertInfoPtr != NULL );
591 
592 		if( !compareDN( subjectCertInfoPtr->issuerName,
593 						issuerCertInfoPtr->subjectName, FALSE, NULL ) )
594 			{
595 			setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
596 						  CRYPT_ERRTYPE_ATTR_VALUE );
597 			return( CRYPT_ERROR_INVALID );
598 			}
599 		}
600 
601 	/* If we're creating a non-self-signed certificate check whether the
602 	   subject's DN is the same as the issuer's DN.  If this is the case
603 	   then the resulting object would appear to be self-signed so we
604 	   disallow it */
605 	if( actions & PRE_CHECK_NONSELFSIGNED_DN )
606 		{
607 		ANALYSER_HINT( issuerCertInfoPtr != NULL );
608 
609 		if( compareDN( issuerCertInfoPtr->subjectName,
610 					   subjectCertInfoPtr->subjectName, FALSE, NULL ) )
611 			{
612 			setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SUBJECTNAME,
613 						  CRYPT_ERRTYPE_ISSUERCONSTRAINT );
614 			return( CRYPT_ERROR_INVALID );
615 			}
616 		}
617 
618 	/* Check that the serial number is present */
619 	if( actions & PRE_CHECK_SERIALNO )
620 		{
621 #ifdef USE_CERTREQ
622 		if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
623 			{
624 			if( subjectCertInfoPtr->cCertReq->serialNumberLength <= 0 )
625 				{
626 				setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
627 							  CRYPT_ERRTYPE_ATTR_ABSENT );
628 				return( CRYPT_ERROR_NOTINITED );
629 				}
630 			}
631 		else
632 #endif /* USE_CERTREQ */
633 			{
634 			if( subjectCertInfoPtr->cCertCert->serialNumberLength <= 0 )
635 				{
636 				setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
637 							  CRYPT_ERRTYPE_ATTR_ABSENT );
638 				return( CRYPT_ERROR_NOTINITED );
639 				}
640 			}
641 		}
642 
643 	/* Check that the validity/revocation information is present */
644 #ifdef USE_CERTVAL
645 	if( actions & PRE_CHECK_VALENTRIES )
646 		{
647 		if( subjectCertInfoPtr->cCertVal->validityInfo == NULL )
648 			{
649 			setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
650 						  CRYPT_ERRTYPE_ATTR_ABSENT );
651 			return( CRYPT_ERROR_NOTINITED );
652 			}
653 		}
654 #endif /* USE_CERTVAL */
655 #ifdef USE_CERTREV
656 	if( actions & PRE_CHECK_REVENTRIES )
657 		{
658 		if( subjectCertInfoPtr->cCertRev->revocations == NULL )
659 			{
660 			setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
661 						  CRYPT_ERRTYPE_ATTR_ABSENT );
662 			return( CRYPT_ERROR_NOTINITED );
663 			}
664 		}
665 #endif /* USE_CERTREV */
666 
667 	/* Now that we've set up the attributes, perform the remainder of the
668 	   checks.  Because RTCS is a CMS standard rather than PKIX the RTCS
669 	   attributes are CMS rather than certificate attributes */
670 	if( subjectCertInfoPtr->attributes != NULL )
671 		{
672 		status = checkAttributes( ( subjectCertInfoPtr->type == \
673 									CRYPT_CERTTYPE_RTCS_REQUEST ) ? \
674 								  ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE,
675 								  subjectCertInfoPtr->attributes,
676 								  &subjectCertInfoPtr->errorLocus,
677 								  &subjectCertInfoPtr->errorType );
678 		if( cryptStatusError( status ) )
679 			return( status );
680 		}
681 	status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr, FALSE,
682 						&subjectCertInfoPtr->errorLocus,
683 						&subjectCertInfoPtr->errorType );
684 	if( cryptStatusError( status ) )
685 		return( status );
686 
687 	/* If it's a certificate or certificate chain remember that it's been
688 	   checked at full compliance level (or at least as full as we're
689 	   configured for).  This short-circuits the need to perform excessive
690 	   levels of checking if the caller wants to re-check it after it's
691 	   been signed */
692 	if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
693 		subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
694 		{
695 		subjectCertInfoPtr->cCertCert->maxCheckLevel = \
696 									CRYPT_COMPLIANCELEVEL_PKIX_FULL;
697 		}
698 
699 	return( status );
700 	}
701 #endif /* USE_CERTIFICATES */
702