cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
certsign.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate Signing Routines *
4 * Copyright Peter Gutmann 1997-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "cert.h"
10  #include "asn1.h"
11 #else
12  #include "cert/cert.h"
13  #include "enc_dec/asn1.h"
14 #endif /* Compiler-specific includes */
15 
16 #ifdef USE_CERTIFICATES
17 
18 /****************************************************************************
19 * *
20 * Utility Routines *
21 * *
22 ****************************************************************************/
23 
24 /* Recover information normally set up on certificate import. After
25  signing the certificate the data is present without the certificate
26  having been explicitly imported so we have to go back and perform the
27  actions normally performed on certificate import here */
28 
29 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
30 static int recoverCertData( INOUT CERT_INFO *certInfoPtr,
31  IN_ENUM( CRYPT_CERTTYPE ) \
33  IN_BUFFER( encodedCertDataLength ) \
34  const void *encodedCertData,
35  IN_LENGTH_SHORT_MIN( 16 ) \
36  const int encodedCertDataLength )
37  {
38  STREAM stream;
39  int length, status;
40 
41  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
42  assert( isReadPtr( encodedCertData, encodedCertDataLength ) );
43 
44  REQUIRES( certType == CRYPT_CERTTYPE_CERTIFICATE || \
45  certType == CRYPT_CERTTYPE_CERTCHAIN || \
46  certType == CRYPT_CERTTYPE_REQUEST_CERT || \
47  certType == CRYPT_CERTTYPE_PKIUSER );
48  REQUIRES( encodedCertDataLength >= 16 && \
49  encodedCertDataLength < MAX_INTLENGTH_SHORT );
50 
51  /* If there's public-key data stored with the certificate free it since
52  we now have a copy as part of the encoded certificate */
53  if( certInfoPtr->publicKeyData != NULL )
54  {
55  zeroise( certInfoPtr->publicKeyData, certInfoPtr->publicKeyInfoSize );
56  clFree( "recoverCertData", certInfoPtr->publicKeyData );
57  certInfoPtr->publicKeyData = NULL;
58  }
59 
60  /* If it's a CRMF request parse the signed form to locate the start of
61  the encoded DN if there is one (the issuer DN is already set up when
62  the issuer certificate is added) and the public key. The public key
63  is actually something of a special case in that in the CRMF/CMP
64  tradition it has a weird nonstandard tag which means that we can't
65  directly use it elsewhere as a SubjectPublicKeyInfo blob. In order
66  to work around this the code that reads SPKIs allows something other
67  than a plain SEQUENCE for the outer wrapper */
68  if( certType == CRYPT_CERTTYPE_REQUEST_CERT )
69  {
70  sMemConnect( &stream, encodedCertData, encodedCertDataLength );
71  readSequence( &stream, NULL ); /* Outer wrapper */
72  readSequence( &stream, NULL );
73  readUniversal( &stream ); /* Request ID */
74  status = readSequence( &stream, NULL ); /* Inner wrapper */
75  if( cryptStatusOK( status ) && \
76  peekTag( &stream ) == MAKE_CTAG( 4 ) )
77  status = readUniversal( &stream ); /* Validity */
78  if( cryptStatusOK( status ) && \
79  peekTag( &stream ) == MAKE_CTAG( 5 ) )
80  {
81  status = readConstructed( &stream, &length, 5 );
82  if( cryptStatusOK( status ) ) /* Subj.name wrapper */
83  status = sMemGetDataBlock( &stream, &certInfoPtr->subjectDNptr,
84  certInfoPtr->subjectDNsize );
85  ENSURES( cryptStatusOK( status ) );
86  status = readUniversal( &stream ); /* Subject name */
87  }
88  if( cryptStatusOK( status ) && \
89  peekTag( &stream ) != MAKE_CTAG( 6 ) ) /* Public key */
90  status = CRYPT_ERROR_BADDATA;
91  if( cryptStatusOK( status ) )
92  status = sMemGetDataBlock( &stream, &certInfoPtr->publicKeyInfo,
93  certInfoPtr->publicKeyInfoSize );
94  ENSURES( cryptStatusOK( status ) );
95  ENSURES( cryptStatusOK( getStreamObjectLength( &stream, &length ) ) && \
96  length == certInfoPtr->publicKeyInfoSize );
97  sMemDisconnect( &stream );
98 
99  return( CRYPT_OK );
100  }
101 
102  /* If it's PKI user data parse the encoded form to locate the start of
103  the user DN */
104  if( certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER )
105  {
106  sMemConnect( &stream, encodedCertData, encodedCertDataLength );
107  readSequence( &stream, NULL ); /* Outer wrapper */
108  status = readSequence( &stream, &length );
109  if( cryptStatusOK( status ) )
110  status = sMemGetDataBlock( &stream, &certInfoPtr->subjectDNptr,
111  certInfoPtr->subjectDNsize );
112  sMemDisconnect( &stream );
113  ENSURES( cryptStatusOK( status ) );
114 
115  return( CRYPT_OK );
116  }
117 
118  ENSURES( certType == CRYPT_CERTTYPE_CERTIFICATE || \
119  certType == CRYPT_CERTTYPE_CERTCHAIN );
120 
121  /* It's a certificate, parse the signed form to locate the start of the
122  encoded issuer and subject DN and public key (the length is recorded
123  when the certificate data is written but the position of the other
124  elements in the certificate can't be determined until the certificate
125  has been signed) */
126  sMemConnect( &stream, encodedCertData, encodedCertDataLength );
127  readSequence( &stream, NULL ); /* Outer wrapper */
128  status = readSequence( &stream, NULL ); /* Inner wrapper */
129  if( cryptStatusOK( status ) && \
130  peekTag( &stream ) == MAKE_CTAG( 0 ) )
131  readUniversal( &stream ); /* Version */
132  readUniversal( &stream ); /* Serial number */
133  status = readUniversal( &stream ); /* Signature algo */
134  if( cryptStatusOK( status ) )
135  status = sMemGetDataBlock( &stream, &certInfoPtr->issuerDNptr,
136  certInfoPtr->issuerDNsize );
137  ENSURES( cryptStatusOK( status ) );
138  readUniversal( &stream ); /* Issuer DN */
139  status = readUniversal( &stream ); /* Validity */
140  if( cryptStatusOK( status ) )
141  status = sMemGetDataBlock( &stream, &certInfoPtr->subjectDNptr,
142  certInfoPtr->subjectDNsize );
143  ENSURES( cryptStatusOK( status ) );
144  status = readUniversal( &stream ); /* Subject DN */
145  if( cryptStatusOK( status ) )
146  status = sMemGetDataBlock( &stream, &certInfoPtr->publicKeyInfo,
147  certInfoPtr->publicKeyInfoSize );
148  ENSURES( cryptStatusOK( status ) );
149  ENSURES( cryptStatusOK( getStreamObjectLength( &stream, &length ) ) && \
150  length == certInfoPtr->publicKeyInfoSize );
151  sMemDisconnect( &stream );
152 
153  /* Since the certificate may be used for public-key operations as soon
154  as it's signed we have to reconstruct the public-key context and
155  apply to it the constraints that would be applied on import, the
156  latter being done implicitly via the MESSAGE_SETDEPENDENT mechanism */
157  sMemConnect( &stream, certInfoPtr->publicKeyInfo,
158  certInfoPtr->publicKeyInfoSize );
159  status = iCryptReadSubjectPublicKey( &stream,
160  &certInfoPtr->iPubkeyContext,
162  sMemDisconnect( &stream );
163  if( cryptStatusError( status ) )
164  return( status );
165  status = krnlSendMessage( certInfoPtr->objectHandle,
167  &certInfoPtr->iPubkeyContext,
169  if( cryptStatusOK( status ) )
170  certInfoPtr->flags &= ~CERT_FLAG_DATAONLY;
171  return( status );
172  }
173 
174 
175 /* Check the key being used to sign a certificate object */
176 
177 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
178 static int checkSigningKey( INOUT CERT_INFO *certInfoPtr,
180  const BOOLEAN isCertificate,
183  const int complianceLevel )
184  {
185  int status;
186 
187  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
188  assert( isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
189 
190  REQUIRES( complianceLevel >= CRYPT_COMPLIANCELEVEL_OBLIVIOUS && \
191  complianceLevel < CRYPT_COMPLIANCELEVEL_LAST );
192 
193  /* Make sure that the signing key is associated with an issuer
194  certificate rather than some other key-related object like a
195  certificate request */
196  if( issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
197  issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN )
198  return( CRYPT_ARGERROR_VALUE );
199 
200  /* Make sure that the signing key is associated with a completed issuer
201  certificate. If it's a self-signed certificate then we don't have to
202  have a completed certificate present because the self-sign operation
203  hasn't created it yet */
204  if( ( !( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) && \
205  issuerCertInfoPtr->certificate == NULL ) )
206  return( CRYPT_ARGERROR_VALUE );
207 
208  /* If it's an OCSP request or response then the signing certificate has
209  to be valid for signing */
210  if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
211  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
212  {
213  return( checkKeyUsage( issuerCertInfoPtr, CHECKKEY_FLAG_NONE,
214  KEYUSAGE_SIGN, complianceLevel,
215  &certInfoPtr->errorLocus,
216  &certInfoPtr->errorType ) );
217  }
218 
219  /* If it's a non-self-signed object then it must be signed by a CA
220  certificate */
221  if( !( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
222  {
223  status = checkKeyUsage( issuerCertInfoPtr, CHECKKEY_FLAG_CA,
224  isCertificate ? CRYPT_KEYUSAGE_KEYCERTSIGN : \
226  complianceLevel, &certInfoPtr->errorLocus,
227  &certInfoPtr->errorType );
228  if( cryptStatusError( status ) && \
229  certInfoPtr->errorType == CRYPT_ERRTYPE_CONSTRAINT )
230  {
231  /* If there was a constraint problem it's something in the
232  issuer's certificate rather than the certificate being signed
233  so we have to change the error type accordingly. What's
234  reported isn't strictly accurate since the locus is in the
235  issuer rather than subject certificate but it's the best that
236  we can do */
237  certInfoPtr->errorType = CRYPT_ERRTYPE_ISSUERCONSTRAINT;
238  }
239 
240  return( status );
241  }
242 
243  /* It's a self-signed object, there are no further key-related checks
244  required */
245  return( CRYPT_OK );
246  }
247 
248 /****************************************************************************
249 * *
250 * Signing Setup Functions *
251 * *
252 ****************************************************************************/
253 
254 /* Copy a signing certificate chain into the certificate being signed */
255 
257 static int copySigningCertChain( INOUT CERT_INFO *certInfoPtr,
259  {
260  CERT_CERT_INFO *certInfo = certInfoPtr->cCertCert;
261 
262  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
263 
264  REQUIRES( isHandleRangeValid( iSignContext ) );
265 
266  /* If there's a chain of certificates present (for example from a
267  previous signing attempt that wasn't completed due to an error), free
268  them */
269  if( certInfo->chainEnd > 0 )
270  {
271  int i;
272 
273  for( i = 0; i < certInfo->chainEnd && i < MAX_CHAINLENGTH; i++ )
274  krnlSendNotifier( certInfo->chain[ i ], IMESSAGE_DECREFCOUNT );
275  ENSURES( i < MAX_CHAINLENGTH );
276  certInfo->chainEnd = 0;
277  }
278 
279  /* If it's a self-signed certificate it must be the only one in the
280  chain (creating a chain like this doesn't make much sense but we
281  handle it anyway) */
282  if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
283  {
284  if( certInfo->chainEnd > 0 )
285  {
288  return( CRYPT_ERROR_INVALID );
289  }
290 
291  return( CRYPT_OK );
292  }
293 
294  /* Copy the certificate chain into the certificate to be signed */
295  return( copyCertChain( certInfoPtr, iSignContext, FALSE ) );
296  }
297 
298 /* Set up any required timestamp data for a certificate object */
299 
301 static int setCertTimeinfo( INOUT CERT_INFO *certInfoPtr,
302  IN_HANDLE_OPT const CRYPT_CONTEXT iSignContext,
303  const BOOLEAN isCertificate )
304  {
305  const time_t currentTime = ( iSignContext == CRYPT_UNUSED ) ? \
306  getTime() : getReliableTime( iSignContext );
307  int status;
308 
309  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
310 
311  REQUIRES( iSignContext == CRYPT_UNUSED || \
312  isHandleRangeValid( iSignContext ) );
313 
314  /* If it's some certificate variant or CRL/OCSP response and the various
315  timestamps haven't been set yet start them at the current time and
316  give them the default validity period or next update time if these
317  haven't been set. The time used is the local time, this is converted
318  to GMT when we write it to the certificate. Issues like validity
319  period nesting and checking for valid time periods are handled
320  elsewhere */
321  if( ( isCertificate || \
322  certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
323  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE ) && \
324  certInfoPtr->startTime <= MIN_TIME_VALUE )
325  {
326  /* If the time is screwed up we can't provide a signed indication
327  of the time */
328  if( currentTime <= MIN_TIME_VALUE )
329  {
332  return( CRYPT_ERROR_NOTINITED );
333  }
334  certInfoPtr->startTime = currentTime;
335  }
336  if( isCertificate && certInfoPtr->endTime <= MIN_TIME_VALUE )
337  {
338  int validity;
339 
340  status = krnlSendMessage( certInfoPtr->ownerHandle,
341  IMESSAGE_GETATTRIBUTE, &validity,
343  if( cryptStatusError( status ) )
344  return( status );
345  certInfoPtr->endTime = certInfoPtr->startTime + \
346  ( ( time_t ) validity * 86400L );
347  }
348  if( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
349  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
350  {
351  if( certInfoPtr->endTime <= MIN_TIME_VALUE )
352  {
353  if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
354  {
355  /* OCSP responses come directly from the certificate store
356  and represent an atomic (and ephemeral) snapshot of the
357  store state. Because of this the next-update time occurs
358  effectively immediately since the next snapshot could
359  provide a different response */
360  certInfoPtr->endTime = currentTime;
361  }
362  else
363  {
364  int updateInterval;
365 
366  status = krnlSendMessage( certInfoPtr->ownerHandle,
367  IMESSAGE_GETATTRIBUTE, &updateInterval,
369  if( cryptStatusError( status ) )
370  return( status );
371  certInfoPtr->endTime = certInfoPtr->startTime + \
372  ( ( time_t ) updateInterval * 86400L );
373  }
374  }
375 #ifdef USE_CERTREV
376  if( certInfoPtr->cCertRev->revocationTime <= MIN_TIME_VALUE )
377  certInfoPtr->cCertRev->revocationTime = currentTime;
378 #endif /* USE_CERTREV */
379  }
380 
381  return( CRYPT_OK );
382  }
383 
384 
385 /* Perform any final initialisation of the certificate object before we sign
386  it */
387 
389 static int initSignatureInfo( INOUT CERT_INFO *certInfoPtr,
390  IN_OPT const CERT_INFO *issuerCertInfoPtr,
391  IN_HANDLE_OPT const CRYPT_CONTEXT iSignContext,
392  const BOOLEAN isCertificate,
394  IN_ENUM( CRYPT_SIGNATURELEVEL ) \
395  const CRYPT_SIGNATURELEVEL_TYPE signatureLevel,
396  OUT_OPT_LENGTH_SHORT_Z int *extraDataLength )
397  {
398  int status;
399 
400  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
401  assert( issuerCertInfoPtr == NULL || \
402  isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
403  assert( isWritePtr( hashAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
404  assert( extraDataLength == NULL || \
405  isWritePtr( extraDataLength, sizeof( int ) ) );
406 
407  REQUIRES( iSignContext == CRYPT_UNUSED || \
408  isHandleRangeValid( iSignContext ) );
409  REQUIRES( ( signatureLevel == CRYPT_SIGNATURELEVEL_NONE && \
410  extraDataLength == NULL ) || \
411  ( signatureLevel >= CRYPT_SIGNATURELEVEL_SIGNERCERT && \
412  signatureLevel < CRYPT_SIGNATURELEVEL_LAST && \
413  extraDataLength != NULL ) );
414 
415  /* Clear return values */
416  *hashAlgo = CRYPT_ALGO_NONE;
417  if( extraDataLength != NULL )
418  *extraDataLength = 0;
419 
420  /* If we need to include extra data in the signature make sure that it's
421  available and determine how big it'll be. If there's no issuer
422  certificate available and we've been asked for extra signature data
423  we fall back to providing just a raw signature rather than bailing
424  out completely */
425  if( extraDataLength != NULL && issuerCertInfoPtr != NULL )
426  {
427  ENSURES( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT || \
428  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
429 
430  if( signatureLevel == CRYPT_SIGNATURELEVEL_SIGNERCERT )
431  {
432  status = exportCert( NULL, 0, extraDataLength,
434  issuerCertInfoPtr );
435  }
436  else
437  {
439 
440  ENSURES( signatureLevel == CRYPT_SIGNATURELEVEL_ALL );
441 
442  setMessageData( &msgData, NULL, 0 );
443  status = krnlSendMessage( issuerCertInfoPtr->objectHandle,
444  IMESSAGE_CRT_EXPORT, &msgData,
445  CRYPT_ICERTFORMAT_CERTSEQUENCE );
446  if( cryptStatusOK( status ) )
447  *extraDataLength = msgData.length;
448  }
449  if( cryptStatusError( status ) )
450  return( status );
451  }
452 
453  /* If it's a certificate chain copy over the signing certificate(s) */
454  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
455  {
456  status = copySigningCertChain( certInfoPtr, iSignContext );
457  if( cryptStatusError( status ) )
458  return( status );
459  }
460 
461  /* Set up any required timestamps */
462  status = setCertTimeinfo( certInfoPtr, iSignContext, isCertificate );
463  if( cryptStatusError( status ) )
464  return( status );
465 
466  /* If it's a certificate, set up the certificate serial number */
467  if( isCertificate )
468  {
469  status = setSerialNumber( certInfoPtr, NULL, 0 );
470  if( cryptStatusError( status ) )
471  return( status );
472  }
473 
474  /* Determine the hash algorithm to use and if it's a certificate or
475  CRL remember it for when we write the certificate (the value is
476  embedded in the certificate to prevent an obscure attack on unpadded
477  RSA signature algorithms) */
478  status = krnlSendMessage( certInfoPtr->ownerHandle,
479  IMESSAGE_GETATTRIBUTE, hashAlgo,
481  if( cryptStatusError( status ) )
482  return( status );
483  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
484  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
485  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT )
486  certInfoPtr->cCertCert->hashAlgo = *hashAlgo;
487 #ifdef USE_CERTREV
488  else
489  {
490  if( certInfoPtr->type == CRYPT_CERTTYPE_CRL )
491  certInfoPtr->cCertRev->hashAlgo = *hashAlgo;
492  }
493 #endif /* USE_CERTREV */
494 
495  return( CRYPT_OK );
496  }
497 
498 /****************************************************************************
499 * *
500 * Signing Functions *
501 * *
502 ****************************************************************************/
503 
504 #if defined( USE_CERTREQ ) || defined( USE_CERTREV ) || \
505  defined( USE_CERTVAL ) || defined( USE_PKIUSER )
506 
507 /* Pseudo-sign certificate information by writing the outer wrapper around
508  the certificate object data and moving the object into the initialised
509  state */
510 
511 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
512 static int pseudoSignCertificate( INOUT CERT_INFO *certInfoPtr,
514  void *signedObject,
515  IN_LENGTH_SHORT_MIN( 16 ) \
516  const int signedObjectMaxLength,
518  const void *certObject,
519  IN_LENGTH_SHORT_MIN( 16 ) \
520  const int certObjectLength )
521  {
522  STREAM stream;
524 
525  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
526  assert( isWritePtr( signedObject, signedObjectMaxLength ) );
527  assert( isReadPtr( certObject, certObjectLength ) );
528 
529  REQUIRES( signedObjectMaxLength >= 16 && \
530  signedObjectMaxLength < MAX_INTLENGTH_SHORT );
531  REQUIRES( certObjectLength >= 16 && \
532  certObjectLength <= signedObjectMaxLength && \
533  certObjectLength < MAX_INTLENGTH_SHORT );
534 
535  switch( certInfoPtr->type )
536  {
539  /* It's an unsigned OCSP request or PKI user information, write
540  the outer wrapper */
541  signedObjectLength = sizeofObject( certObjectLength );
542  ENSURES( signedObjectLength >= 16 && \
543  signedObjectLength <= signedObjectMaxLength );
544  sMemOpen( &stream, signedObject, signedObjectLength );
545  writeSequence( &stream, certObjectLength );
546  status = swrite( &stream, certObject, certObjectLength );
547  sMemDisconnect( &stream );
548  ENSURES( cryptStatusOK( status ) );
549  if( certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER )
550  {
551  status = recoverCertData( certInfoPtr,
553  signedObject, signedObjectLength );
554  if( cryptStatusError( status ) )
555  return( status );
556  }
557  break;
558 
562  /* It's an RTCS request/response or OCSP response, it's already
563  in the form required */
564  signedObjectLength = certObjectLength;
565  ENSURES( signedObjectLength >= 16 && \
566  signedObjectLength <= signedObjectMaxLength );
567  memcpy( signedObject, certObject, certObjectLength );
568  break;
569 
571  {
572  const int dataSize = certObjectLength + \
573  sizeofObject( sizeofShortInteger( 0 ) );
574 
575  ENSURES( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
576 
577  /* It's an encryption-only key, wrap up the certificate data
578  with an indication that private key POP will be performed via
579  out-of-band means and remember where the encoded data
580  starts */
581  signedObjectLength = sizeofObject( dataSize );
582  ENSURES( signedObjectLength >= 16 && \
583  signedObjectLength <= signedObjectMaxLength );
584  sMemOpen( &stream, signedObject, signedObjectLength );
585  writeSequence( &stream, dataSize );
586  swrite( &stream, certObject, certObjectLength );
587  writeConstructed( &stream, sizeofShortInteger( 0 ), 2 );
588  status = writeShortInteger( &stream, 0, 1 );
589  sMemDisconnect( &stream );
590  ENSURES( cryptStatusOK( status ) );
591  status = recoverCertData( certInfoPtr,
593  signedObject, signedObjectLength );
594  if( cryptStatusError( status ) )
595  return( status );
596 
597  /* Indicate that the pseudo-signature has been checked (since we
598  just created it), this also avoids nasty semantic problems
599  with not-really-signed CRMF requests containing encryption-
600  only keys */
601  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
602  break;
603  }
604 
606  /* Revocation requests can't be signed so the (pseudo-)signed
607  data is just the object data */
608  signedObjectLength = certObjectLength;
609  ENSURES( signedObjectLength >= 16 && \
610  signedObjectLength <= signedObjectMaxLength );
611  memcpy( signedObject, certObject, certObjectLength );
612 
613  /* Since revocation requests can't be signed we mark them as
614  pseudo-signed to avoid any problems that might arise from
615  this */
616  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
617  break;
618 
619  default:
620  retIntError();
621  }
622  certInfoPtr->certificate = signedObject;
623  certInfoPtr->certificateSize = signedObjectLength;
624 
625  /* The object is now (pseudo-)signed and initialised */
626  certInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
627  if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
628  {
629  /* If it's a CRMF request with POP done via out-of-band means we
630  got here via a standard signing action (except that the key was
631  an encryption-only key), don't change the object state since the
632  kernel will do this as the post-signing step */
633  return( CRYPT_OK );
634  }
635  return( krnlSendMessage( certInfoPtr->objectHandle,
637  CRYPT_IATTRIBUTE_INITIALISED ) );
638  }
639 #endif /* USE_CERTREQ || USE_CERTREV || USE_CERTVAL || USE_PKIUSER */
640 
641 /* Sign the certificate information */
642 
643 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 6 ) ) \
644 int signCertInfo( OUT_BUFFER( signedObjectMaxLength, *signedObjectLength ) \
645  void *signedObject,
646  IN_LENGTH const int signedObjectMaxLength,
647  OUT_LENGTH_Z int *signedObjectLength,
648  IN_BUFFER( objectLength ) const void *object,
649  IN_LENGTH const int objectLength,
650  INOUT CERT_INFO *certInfoPtr,
651  IN_HANDLE const CRYPT_CONTEXT iSignContext,
652  IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
653  IN_ENUM( CRYPT_SIGNATURELEVEL ) \
654  const CRYPT_SIGNATURELEVEL_TYPE signatureLevel,
655  IN_LENGTH_SHORT_Z const int extraDataLength,
656  const CERT_INFO *issuerCertInfoPtr )
657  {
658  STREAM stream;
659  const int extraDataType = \
660  ( signatureLevel == CRYPT_SIGNATURELEVEL_SIGNERCERT ) ? \
661  CRYPT_CERTFORMAT_CERTIFICATE : CRYPT_ICERTFORMAT_CERTSEQUENCE;
662  int status;
663 
664  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
665  assert( isWritePtr( signedObject, signedObjectMaxLength ) );
666  assert( isWritePtr( signedObjectLength, sizeof( int ) ) );
667  assert( isReadPtr( object, objectLength ) && \
668  !cryptStatusError( checkObjectEncoding( object, \
669  objectLength ) ) );
670  assert( issuerCertInfoPtr == NULL || \
671  isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
672 
673  REQUIRES( signedObjectMaxLength >= 16 && \
674  signedObjectMaxLength < MAX_INTLENGTH_SHORT );
675  REQUIRES( objectLength >= 16 && \
676  objectLength <= signedObjectMaxLength && \
677  objectLength < MAX_INTLENGTH_SHORT );
678  REQUIRES( isHandleRangeValid( iSignContext ) );
679  REQUIRES( isHashAlgo( hashAlgo ) );
680  REQUIRES( signatureLevel >= CRYPT_SIGNATURELEVEL_NONE && \
681  signatureLevel < CRYPT_SIGNATURELEVEL_LAST );
682  REQUIRES( extraDataLength >= 0 && \
683  extraDataLength < MAX_INTLENGTH_SHORT );
684 
685  /* Sign the certificate information. CRMF and OCSP use a b0rken
686  signature format (the authors couldn't quite manage a cut & paste of
687  two lines of text) so if it's one of these we have to use nonstandard
688  formatting */
689  if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT || \
690  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST )
691  {
693 
694  if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
695  {
696  /* [1] SEQUENCE */
697  setX509FormatInfo( &formatInfo, 1, FALSE );
698  }
699  else
700  {
701  /* [0] EXPLICIT SEQUENCE */
702  setX509FormatInfo( &formatInfo, 0, TRUE );
703  }
704  if( signatureLevel == CRYPT_SIGNATURELEVEL_SIGNERCERT )
705  {
706  formatInfo.extraLength = ( int ) \
707  sizeofObject( sizeofObject( extraDataLength ) );
708  }
709  else
710  {
711  if( signatureLevel == CRYPT_SIGNATURELEVEL_ALL )
712  {
713  formatInfo.extraLength = ( int ) \
714  sizeofObject( extraDataLength );
715  }
716  }
717  status = createX509signature( signedObject, signedObjectMaxLength,
718  signedObjectLength, object, objectLength,
719  iSignContext, hashAlgo, &formatInfo );
720  }
721  else
722  {
723  /* It's a standard signature */
724  status = createX509signature( signedObject, signedObjectMaxLength,
725  signedObjectLength, object, objectLength,
726  iSignContext, hashAlgo, NULL );
727  }
728  if( cryptStatusError( status ) )
729  return( cryptArgError( status ) ? CRYPT_ARGERROR_VALUE : status );
730 
731  /* If there's no extra data to handle, we're done */
732  if( extraDataLength <= 0 )
733  {
735  checkObjectEncoding( signedObject, \
736  *signedObjectLength ) ) );
737  return( CRYPT_OK );
738  }
739 
740  /* If we need to include extra data with the signature attach it to the
741  end of the signature */
742  ENSURES( rangeCheck( *signedObjectLength,
743  signedObjectMaxLength - *signedObjectLength,
744  signedObjectMaxLength ) );
745  sMemOpen( &stream, ( BYTE * ) signedObject + *signedObjectLength,
746  signedObjectMaxLength - *signedObjectLength );
747  if( signatureLevel == CRYPT_SIGNATURELEVEL_SIGNERCERT )
748  {
749  writeConstructed( &stream, sizeofObject( extraDataLength ), 0 );
750  writeSequence( &stream, extraDataLength );
751  }
752  else
753  {
754  ENSURES( signatureLevel == CRYPT_SIGNATURELEVEL_ALL );
755 
756  writeConstructed( &stream, extraDataLength, 0 );
757  }
758  status = exportCertToStream( &stream, issuerCertInfoPtr->objectHandle,
759  extraDataType );
760  if( cryptStatusOK( status ) )
761  *signedObjectLength += stell( &stream );
762  sMemDisconnect( &stream );
763  if( cryptStatusError( status ) )
764  return( status );
766  checkObjectEncoding( signedObject, *signedObjectLength ) ) );
767  return( CRYPT_OK );
768  }
769 
770 /* Sign a certificate object */
771 
773 int signCert( INOUT CERT_INFO *certInfoPtr,
774  IN_HANDLE_OPT const CRYPT_CONTEXT iSignContext )
775  {
777  CERT_INFO *issuerCertInfoPtr = NULL;
778  STREAM stream;
779  WRITECERT_FUNCTION writeCertFunction;
780 #ifdef USE_CERTREV
781  const CRYPT_SIGNATURELEVEL_TYPE signatureLevel = \
782  ( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST ) ? \
783  certInfoPtr->cCertRev->signatureLevel : \
785 #else
787 #endif /* USE_CERTREV */
788  const BOOLEAN isCertificate = \
789  ( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
790  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
791  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN ) ? TRUE : FALSE;
792  BOOLEAN issuerCertAcquired = FALSE, nonSigningKey = FALSE;
793  BYTE certObjectBuffer[ 1024 + 8 ], *certObjectPtr = certObjectBuffer;
794  void *signedCertObject;
795  int certObjectLength = DUMMY_INIT, signedCertObjectLength;
796  int signedCertAllocSize, extraDataLength = 0, complianceLevel, status;
797 
798  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
799 
800  REQUIRES( iSignContext == CRYPT_UNUSED || \
801  isHandleRangeValid( iSignContext ) );
802  REQUIRES( certInfoPtr->certificate == NULL );
803 
804  /* Determine how much checking we need to perform */
805  status = krnlSendMessage( certInfoPtr->ownerHandle,
806  IMESSAGE_GETATTRIBUTE, &complianceLevel,
808  if( cryptStatusError( status ) )
809  return( status );
810 
811  /* If it's a non-signing key we have to create a special format of
812  certificate request that isn't signed but contains an indication that
813  the private key POP will be performed by out-of-band means. We also
814  have to check for the iSignContext being absent to handle OCSP
815  requests for which the signature is optional so there may be no
816  signing key present */
817  if( iSignContext == CRYPT_UNUSED || \
819  NULL, MESSAGE_CHECK_PKC_SIGN ) ) )
820  nonSigningKey = TRUE;
821 
822  /* Obtain the issuer certificate from the private key if necessary
823  (aliena nobis, nostra plus aliis placent) */
824  if( isCertificate || \
825  certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
826  ( ( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
827  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE ) && \
828  !nonSigningKey ) )
829  {
830  /* If it's a self-signed certificate then the issuer is also the
831  subject */
832  if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
833  issuerCertInfoPtr = certInfoPtr;
834  else
835  {
837 
838  /* Get the data-only certificate from the context */
839  status = krnlSendMessage( iSignContext, IMESSAGE_GETDEPENDENT,
840  &dataOnlyCert, OBJECT_TYPE_CERTIFICATE );
841  if( cryptStatusError( status ) )
842  return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
843  CRYPT_ARGERROR_VALUE : status );
844  status = krnlAcquireObject( dataOnlyCert, OBJECT_TYPE_CERTIFICATE,
845  ( void ** ) &issuerCertInfoPtr,
847  if( cryptStatusError( status ) )
848  return( status );
849  issuerCertAcquired = TRUE;
850  }
851 
852  /* Check the signing key */
853  status = checkSigningKey( certInfoPtr, issuerCertInfoPtr,
854  isCertificate, complianceLevel );
855  if( cryptStatusError( status ) )
856  {
857  if( issuerCertAcquired )
858  krnlReleaseObject( issuerCertInfoPtr->objectHandle );
859  return( status );
860  }
861  }
862 
863  /* Perform any final initialisation of the certificate object before we
864  sign it */
865  status = initSignatureInfo( certInfoPtr, issuerCertInfoPtr,
866  iSignContext, isCertificate, &hashAlgo,
867  signatureLevel,
868  ( signatureLevel > CRYPT_SIGNATURELEVEL_NONE ) ? \
869  &extraDataLength : NULL );
870  if( cryptStatusError( status ) )
871  {
872  if( issuerCertAcquired )
873  krnlReleaseObject( issuerCertInfoPtr->objectHandle );
874  return( status );
875  }
876 
877  /* Select the function to use to write the certificate object to be
878  signed */
879  writeCertFunction = getCertWriteFunction( certInfoPtr->type );
880  if( writeCertFunction == NULL )
881  {
882  if( issuerCertAcquired )
883  krnlReleaseObject( issuerCertInfoPtr->objectHandle );
884  retIntError();
885  }
886 
887  /* Determine how big the encoded certificate information will be,
888  allocate memory for it and the full signed certificate, and write the
889  encoded certificate information */
890  sMemNullOpen( &stream );
891  status = writeCertFunction( &stream, certInfoPtr, issuerCertInfoPtr,
892  iSignContext );
893  if( cryptStatusOK( status ) )
894  certObjectLength = stell( &stream );
895  sMemClose( &stream );
896  if( cryptStatusError( status ) )
897  {
898  if( issuerCertAcquired )
899  krnlReleaseObject( issuerCertInfoPtr->objectHandle );
900  return( status );
901  }
902  signedCertAllocSize = certObjectLength + 1024 + extraDataLength;
903  if( certObjectLength > 1024 )
904  certObjectPtr = clDynAlloc( "signCert", certObjectLength );
905  signedCertObject = clAlloc( "signCert", signedCertAllocSize );
906  if( certObjectPtr == NULL || signedCertObject == NULL )
907  {
908  if( certObjectPtr != NULL && certObjectPtr != certObjectBuffer )
909  clFree( "signCert", certObjectPtr );
910  if( signedCertObject != NULL )
911  clFree( "signCert", signedCertObject );
912  if( issuerCertAcquired )
913  krnlReleaseObject( issuerCertInfoPtr->objectHandle );
914  return( CRYPT_ERROR_MEMORY );
915  }
916  sMemOpen( &stream, certObjectPtr, certObjectLength );
917  status = writeCertFunction( &stream, certInfoPtr, issuerCertInfoPtr,
918  iSignContext );
919  ENSURES( cryptStatusError( status ) || \
920  certObjectLength == stell( &stream ) );
921  sMemDisconnect( &stream );
922  if( issuerCertAcquired )
923  krnlReleaseObject( issuerCertInfoPtr->objectHandle );
924  if( cryptStatusError( status ) )
925  {
926  zeroise( certObjectPtr, certObjectLength );
927  if( certObjectPtr != certObjectBuffer )
928  clFree( "signCert", certObjectPtr );
929  clFree( "signCert", signedCertObject );
930  return( status );
931  }
932  ENSURES( !cryptStatusError( checkObjectEncoding( certObjectPtr, \
933  certObjectLength ) ) );
934 
935 #if defined( USE_CERTREQ ) || defined( USE_CERTREV ) || \
936  defined( USE_CERTVAL ) || defined( USE_PKIUSER )
937  /* If there's no signing key present we pseudo-sign the certificate
938  information by writing the outer wrapper and moving the object into
939  the initialised state */
940  if( nonSigningKey )
941  {
942  status = pseudoSignCertificate( certInfoPtr, signedCertObject,
943  signedCertAllocSize, certObjectPtr,
944  certObjectLength );
945  zeroise( certObjectPtr, certObjectLength );
946  if( certObjectPtr != certObjectBuffer )
947  clFree( "signCert", certObjectPtr );
948  if( cryptStatusError( status ) )
949  return( status );
950  ANALYSER_HINT( certInfoPtr->certificate != NULL );
952  checkObjectEncoding( certInfoPtr->certificate, \
953  certInfoPtr->certificateSize ) ) );
954  return( CRYPT_OK );
955  }
956 #endif /* USE_CERTREQ || USE_CERTREV || USE_CERTVAL || USE_PKIUSER */
957 
958  /* Sign the certificate information */
959  status = signCertInfo( signedCertObject, signedCertAllocSize,
960  &signedCertObjectLength, certObjectPtr,
961  certObjectLength, certInfoPtr, iSignContext,
962  hashAlgo, signatureLevel, extraDataLength,
963  issuerCertInfoPtr );
964  zeroise( certObjectPtr, certObjectLength );
965  if( certObjectPtr != certObjectBuffer )
966  clFree( "signCert", certObjectPtr );
967  if( cryptStatusError( status ) )
968  {
969  clFree( "signCert", signedCertObject );
970  return( status );
971  }
972  certInfoPtr->certificate = signedCertObject;
973  certInfoPtr->certificateSize = signedCertObjectLength;
974 
975  /* If it's a certification request it's now self-signed. In addition
976  the signature has been checked since we've just created it */
977  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
978  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
979  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
980  certInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
981 
982 #if 0 /* 15/6/04 Only the root should be marked as self-signed, having
983  supposedly self-signed certificates inside the chain
984  causes problems when trying to detect pathkludge
985  certificates */
986  /* If it's a certificate chain and the root is self-signed then the
987  entire chain counts as self-signed */
988  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
989  {
990  int selfSigned;
991 
992  status = krnlSendMessage( \
993  certInfoPtr->cCertCert->chain[ certInfoPtr->cCertCert->chainEnd - 1 ],
994  IMESSAGE_GETATTRIBUTE, &selfSigned,
996  if( cryptStatusOK( status ) && selfSigned )
997  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
998  }
999 #endif /* 0 */
1000 
1001  /* If it's not an object type with special-case post-signing
1002  requirements we're done */
1003  if( certInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
1004  certInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN && \
1005  certInfoPtr->type != CRYPT_CERTTYPE_REQUEST_CERT )
1006  return( CRYPT_OK );
1007 
1008  /* Recover information such as pointers to encoded certificate data */
1009  return( recoverCertData( certInfoPtr, certInfoPtr->type,
1010  signedCertObject, signedCertObjectLength ) );
1011  }
1012 #endif /* USE_CERTIFICATES */