cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pkcs15_atwr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PKCS #15 Attribute Write Routines *
4 * Copyright Peter Gutmann 1996-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "keyset.h"
12  #include "pkcs15.h"
13 #else
14  #include "crypt.h"
15  #include "enc_dec/asn1.h"
16  #include "keyset/keyset.h"
17  #include "keyset/pkcs15.h"
18 #endif /* Compiler-specific includes */
19 
20 #ifdef USE_PKCS15
21 
22 /****************************************************************************
23 * *
24 * Utility Functions *
25 * *
26 ****************************************************************************/
27 
28 /* Get assorted ID information from a context or certificate */
29 
31 static int getKeyIDs( INOUT PKCS15_INFO *pkcs15infoPtr,
33  {
35  BYTE sKIDbuffer[ CRYPT_MAX_HASHSIZE + 8 ];
36  int status;
37 
38  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
39 
40  REQUIRES( isHandleRangeValid( iCryptContext ) );
41 
42  /* Get various pieces of information from the object. The information
43  may already have been set up earlier on so we only set it if this is
44  a newly-added key. We use a guard for the existence of both a label
45  and an ID since there may be a pre-set user ID (which isn't the same
46  as the key ID) present for implicitly created keys in user keysets */
47  if( pkcs15infoPtr->labelLength <= 0 )
48  {
49  setMessageData( &msgData, pkcs15infoPtr->label, CRYPT_MAX_TEXTSIZE );
50  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
51  &msgData, CRYPT_CTXINFO_LABEL );
52  if( cryptStatusError( status ) )
53  return( status );
54  pkcs15infoPtr->labelLength = msgData.length;
55  setMessageData( &msgData, pkcs15infoPtr->keyID, CRYPT_MAX_HASHSIZE );
56  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
57  &msgData, CRYPT_IATTRIBUTE_KEYID );
58  if( cryptStatusError( status ) )
59  return( status );
60  pkcs15infoPtr->keyIDlength = msgData.length;
61  }
62  if( pkcs15infoPtr->iDlength <= 0 && pkcs15infoPtr->keyIDlength > 0 )
63  {
64  memcpy( pkcs15infoPtr->iD, pkcs15infoPtr->keyID,
65  pkcs15infoPtr->keyIDlength );
66  pkcs15infoPtr->iDlength = pkcs15infoPtr->keyIDlength;
67  }
68  if( pkcs15infoPtr->pgp2KeyIDlength <= 0 )
69  {
70  setMessageData( &msgData, pkcs15infoPtr->pgp2KeyID, PGP_KEYID_SIZE );
71  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
72  &msgData, CRYPT_IATTRIBUTE_KEYID_PGP2 );
73  if( cryptStatusOK( status ) )
74  {
75  /* Not present for all key types so an error isn't fatal */
76  pkcs15infoPtr->pgp2KeyIDlength = msgData.length;
77  }
78  }
79  if( pkcs15infoPtr->openPGPKeyIDlength <= 0 )
80  {
81  setMessageData( &msgData, pkcs15infoPtr->openPGPKeyID, PGP_KEYID_SIZE );
82  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
83  &msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
84  if( cryptStatusOK( status ) )
85  {
86  /* Not present for all key types so an error isn't fatal */
87  pkcs15infoPtr->openPGPKeyIDlength = msgData.length;
88  }
89  }
90 
91  /* The subjectKeyIdentifier, if present, may not be the same as the
92  keyID if the certificate that it's in has come from a CA that does
93  strange things with the sKID so we try and read this value and if
94  it's present override the implicit sKID (== keyID) value with the
95  actual sKID */
96  setMessageData( &msgData, sKIDbuffer, CRYPT_MAX_HASHSIZE );
97  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
99  if( cryptStatusOK( status ) )
100  {
101  memcpy( pkcs15infoPtr->keyID, sKIDbuffer, msgData.length );
102  pkcs15infoPtr->keyIDlength = msgData.length;
103  }
104 
105  return( CRYPT_OK );
106  }
107 
108 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 5 ) ) \
109 static int getCertIDs( INOUT PKCS15_INFO *pkcs15infoPtr,
111  OUT BOOLEAN *isCA,
112  OUT BOOLEAN *trustedImplicit,
113  OUT int *trustedUsage )
114  {
115  int status;
116 
117  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
118  assert( isWritePtr( isCA, sizeof( BOOLEAN ) ) );
119  assert( isWritePtr( trustedImplicit, sizeof( BOOLEAN ) ) );
120  assert( isWritePtr( trustedUsage, sizeof( int ) ) );
121 
122  REQUIRES( isHandleRangeValid( iCryptCert ) );
123 
124  /* Clear return values */
125  *isCA = *trustedImplicit = FALSE;
126  *trustedUsage = CRYPT_UNUSED;
127 
128  /* Get various pieces of status information from the certificate */
129  status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE, isCA,
131  if( status == CRYPT_ERROR_NOTFOUND )
132  {
133  *isCA = FALSE;
134  status = CRYPT_OK;
135  }
136  if( cryptStatusOK( status ) )
137  {
138  status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
139  trustedUsage, CRYPT_CERTINFO_TRUSTED_USAGE );
140  if( status == CRYPT_ERROR_NOTFOUND )
141  {
142  /* If there's no trusted usage defined, don't store a trust
143  setting */
144  *trustedUsage = CRYPT_UNUSED;
145  status = CRYPT_OK;
146  }
147  }
148  if( cryptStatusOK( status ) )
149  {
150  status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
151  &trustedImplicit, CRYPT_CERTINFO_TRUSTED_IMPLICIT );
152  if( status == CRYPT_ERROR_NOTFOUND )
153  {
154  /* If it's not implicitly trusted, don't store a trust setting */
155  *trustedImplicit = FALSE;
156  status = CRYPT_OK;
157  }
158  }
159  if( cryptStatusOK( status ) )
160  status = getValidityInfo( pkcs15infoPtr, iCryptCert );
161  if( cryptStatusError( status ) )
162  return( status );
163 
164  /* If we're adding a standalone certificate then the iD and keyID won't
165  have been set up yet so we need to set these up as well. Since the
166  certificate could be a data-only one we create the iD ourselves from
167  the encoded public key components rather than trying to read an
168  associated context's keyID attribute. For similar reasons we
169  specifically don't try and read the PGP ID information since for a
170  certificate chain it'll come from the context of the leaf certificate
171  rather than the current certificate (in any case they're not
172  necessary since none of the certificates in the chain will be PGP
173  keys) */
174  if( pkcs15infoPtr->iDlength <= 0 )
175  {
176  status = getCertID( iCryptCert, CRYPT_IATTRIBUTE_SPKI,
177  pkcs15infoPtr->iD, KEYID_SIZE,
178  &pkcs15infoPtr->iDlength );
179  if( cryptStatusError( status ) )
180  return( status );
181  }
182  if( pkcs15infoPtr->keyIDlength <= 0 )
183  {
185 
186  setMessageData( &msgData, pkcs15infoPtr->keyID, CRYPT_MAX_HASHSIZE );
187  status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
189  if( cryptStatusOK( status ) )
190  pkcs15infoPtr->keyIDlength = msgData.length;
191  else
192  {
193  memcpy( pkcs15infoPtr->keyID, pkcs15infoPtr->iD,
194  pkcs15infoPtr->iDlength );
195  pkcs15infoPtr->keyIDlength = pkcs15infoPtr->iDlength;
196  }
197  }
198 
199  /* Get the various other IDs for the certificate */
200  status = getCertID( iCryptCert, CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER,
201  pkcs15infoPtr->iAndSID, KEYID_SIZE,
202  &pkcs15infoPtr->iAndSIDlength );
203  if( cryptStatusOK( status ) )
204  status = getCertID( iCryptCert, CRYPT_IATTRIBUTE_SUBJECT,
205  pkcs15infoPtr->subjectNameID, KEYID_SIZE,
206  &pkcs15infoPtr->subjectNameIDlength );
207  if( cryptStatusOK( status ) )
208  status = getCertID( iCryptCert, CRYPT_IATTRIBUTE_ISSUER,
209  pkcs15infoPtr->issuerNameID, KEYID_SIZE,
210  &pkcs15infoPtr->issuerNameIDlength );
211  return( status );
212  }
213 
214 /* Get the PKCS #15 key usage flags for a context */
215 
216 CHECK_RETVAL \
217 static int getKeyUsageFlags( IN_HANDLE const CRYPT_HANDLE iCryptContext,
218  IN_FLAGS( PKCS15_USAGE ) const int privKeyUsage )
219  {
221  int keyUsage = PKSC15_USAGE_FLAG_NONE, value, status;
222 
223  REQUIRES( isHandleRangeValid( iCryptContext ) );
224  REQUIRES( privKeyUsage >= PKSC15_USAGE_FLAG_NONE && \
225  privKeyUsage < PKCS15_USAGE_FLAG_MAX );
226 
227  /* There's one special-case situation in which there won't be any usage
228  information available and that's when we've been passed a dummy
229  context that's used to contain key metadata for a crypto device. If
230  this is the case, we allow any usage that the algorithm allows, it's
231  up to the device (which we don't have any control over) to set more
232  specific restrictions */
233  setMessageData( &msgData, NULL, 0 );
234  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
235  &msgData, CRYPT_IATTRIBUTE_DEVICESTORAGEID );
236  if( cryptStatusOK( status ) )
237  {
238  int pkcAlgo;
239 
240  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
241  &pkcAlgo, CRYPT_CTXINFO_ALGO );
242  if( cryptStatusError( status ) )
243  return( status );
244  switch( pkcAlgo )
245  {
246  case CRYPT_ALGO_DH:
247  return( PKCS15_USAGE_DERIVE );
248 
249  case CRYPT_ALGO_RSA:
252 
253  case CRYPT_ALGO_DSA:
255 
256  case CRYPT_ALGO_ELGAMAL:
258  }
259  retIntError();
260  }
261 
262  /* Obtaining the usage flags gets a bit complicated because they're a
263  mixture of parts of X.509 and PKCS #11 flags (and the X.509 -> PKCS
264  #15 mapping isn't perfect, see for example key agreement) so we have
265  to build them up from bits and pieces pulled in from all over the
266  place */
267  if( cryptStatusOK( krnlSendMessage( iCryptContext, IMESSAGE_CHECK,
268  NULL, MESSAGE_CHECK_PKC_ENCRYPT ) ) )
269  keyUsage = PKCS15_USAGE_ENCRYPT;
270  if( cryptStatusOK( krnlSendMessage( iCryptContext, IMESSAGE_CHECK,
271  NULL, MESSAGE_CHECK_PKC_DECRYPT ) ) )
272  keyUsage |= PKCS15_USAGE_DECRYPT;
273  if( cryptStatusOK( krnlSendMessage( iCryptContext, IMESSAGE_CHECK,
274  NULL, MESSAGE_CHECK_PKC_SIGN ) ) )
275  keyUsage |= PKCS15_USAGE_SIGN;
276  if( cryptStatusOK( krnlSendMessage( iCryptContext, IMESSAGE_CHECK,
277  NULL, MESSAGE_CHECK_PKC_SIGCHECK ) ) )
278  keyUsage |= PKCS15_USAGE_VERIFY;
279  if( cryptStatusOK( krnlSendMessage( iCryptContext, IMESSAGE_CHECK,
280  NULL, MESSAGE_CHECK_PKC_KA_EXPORT ) ) || \
282  NULL, MESSAGE_CHECK_PKC_KA_IMPORT ) ) )
283  keyUsage |= PKCS15_USAGE_DERIVE; /* I don't think so Tim */
284  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, &value,
286  if( cryptStatusOK( status ) && \
287  ( value & CRYPT_KEYUSAGE_NONREPUDIATION ) )
288  {
289  /* This may be a raw key or a certificate with no keyUsage present
290  so a failure to read the usage attribute isn't a problem */
291  keyUsage |= PKCS15_USAGE_NONREPUDIATION;
292  }
293 
294  /* If the key ends up being unusable, tell the caller */
295  if( keyUsage <= PKSC15_USAGE_FLAG_NONE )
296  return( 0 );
297 
298  /* If this is a public-key object which is updating a private-key one
299  then the only key usages that we'll have found are public-key ones.
300  To ensure that we don't disable use of the private-key object we copy
301  across private-key usages where corresponding public-key ones are
302  enabled. This is used, for example, when updating an unrestricted-
303  usage raw private key with a restricted-usage public key, e.g. from a
304  certificate */
305  if( cryptStatusError( krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
307  {
308  if( keyUsage & PKCS15_USAGE_ENCRYPT )
309  keyUsage |= privKeyUsage & PKCS15_USAGE_DECRYPT;
310  if( keyUsage & PKCS15_USAGE_VERIFY )
311  keyUsage |= privKeyUsage & PKCS15_USAGE_SIGN;
312  }
313 
314  return( keyUsage );
315  }
316 
317 /****************************************************************************
318 * *
319 * Write PKCS #15 Attributes *
320 * *
321 ****************************************************************************/
322 
323 /* Write PKCS #15 identifier values */
324 
326 static int sizeofObjectIDs( const PKCS15_INFO *pkcs15infoPtr )
327  {
328  int identifierSize;
329 
330  assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
331 
332  identifierSize = ( int ) \
333  sizeofObject( \
335  sizeofObject( pkcs15infoPtr->keyIDlength ) );
336  if( pkcs15infoPtr->iAndSIDlength > 0 )
337  identifierSize += ( int ) \
338  sizeofObject( \
340  sizeofObject( pkcs15infoPtr->iAndSIDlength ) );
341  if( pkcs15infoPtr->issuerNameIDlength > 0 )
342  identifierSize += ( int ) \
343  sizeofObject( \
345  sizeofObject( pkcs15infoPtr->issuerNameIDlength ) );
346  if( pkcs15infoPtr->subjectNameIDlength > 0 )
347  identifierSize += ( int ) \
348  sizeofObject( \
350  sizeofObject( pkcs15infoPtr->subjectNameIDlength ) );
351  if( pkcs15infoPtr->pgp2KeyIDlength > 0 )
352  identifierSize += ( int ) \
353  sizeofObject( \
355  sizeofObject( pkcs15infoPtr->pgp2KeyIDlength ) );
356  if( pkcs15infoPtr->openPGPKeyIDlength > 0 )
357  identifierSize += ( int ) \
358  sizeofObject( \
360  sizeofObject( pkcs15infoPtr->openPGPKeyIDlength ) );
361 
362  return( identifierSize );
363  }
364 
365 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
366 static int writeObjectIDs( INOUT STREAM *stream,
367  const PKCS15_INFO *pkcs15infoPtr,
369  IN_TAG const int tag )
370  {
371  int status;
372 
373  assert( isWritePtr( stream, sizeof( STREAM ) ) );
374  assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
375 
376  REQUIRES( length >= MIN_OBJECT_SIZE && length < MAX_INTLENGTH_SHORT );
377  REQUIRES( tag >= 0 && tag < MAX_TAG_VALUE );
378 
379  writeConstructed( stream, length, tag );
380  writeSequence( stream,
382  sizeofObject( pkcs15infoPtr->keyIDlength ) );
383  writeShortInteger( stream, PKCS15_KEYID_SUBJECTKEYIDENTIFIER,
384  DEFAULT_TAG );
385  status = writeOctetString( stream, pkcs15infoPtr->keyID,
386  pkcs15infoPtr->keyIDlength, DEFAULT_TAG );
387  if( pkcs15infoPtr->iAndSIDlength > 0 )
388  {
389  writeSequence( stream,
391  sizeofObject( pkcs15infoPtr->iAndSIDlength ) );
392  writeShortInteger( stream, PKCS15_KEYID_ISSUERANDSERIALNUMBERHASH,
393  DEFAULT_TAG );
394  status = writeOctetString( stream, pkcs15infoPtr->iAndSID,
395  pkcs15infoPtr->iAndSIDlength,
396  DEFAULT_TAG );
397  }
398  if( pkcs15infoPtr->issuerNameIDlength > 0 )
399  {
400  writeSequence( stream,
402  sizeofObject( pkcs15infoPtr->issuerNameIDlength ) );
403  writeShortInteger( stream, PKCS15_KEYID_ISSUERNAMEHASH, DEFAULT_TAG );
404  status = writeOctetString( stream, pkcs15infoPtr->issuerNameID,
405  pkcs15infoPtr->issuerNameIDlength,
406  DEFAULT_TAG );
407  }
408  if( pkcs15infoPtr->subjectNameIDlength > 0 )
409  {
410  writeSequence( stream,
412  sizeofObject( pkcs15infoPtr->subjectNameIDlength ) );
413  writeShortInteger( stream, PKCS15_KEYID_SUBJECTNAMEHASH, DEFAULT_TAG );
414  status = writeOctetString( stream, pkcs15infoPtr->subjectNameID,
415  pkcs15infoPtr->subjectNameIDlength,
416  DEFAULT_TAG );
417  }
418  if( pkcs15infoPtr->pgp2KeyIDlength > 0 )
419  {
420  writeSequence( stream, sizeofShortInteger( PKCS15_KEYID_PGP2 ) + \
421  sizeofObject( pkcs15infoPtr->pgp2KeyIDlength ) );
422  writeShortInteger( stream, PKCS15_KEYID_PGP2, DEFAULT_TAG );
423  status = writeOctetString( stream, pkcs15infoPtr->pgp2KeyID,
424  pkcs15infoPtr->pgp2KeyIDlength,
425  DEFAULT_TAG );
426  }
427  if( pkcs15infoPtr->openPGPKeyIDlength > 0 )
428  {
429  writeSequence( stream, sizeofShortInteger( PKCS15_KEYID_OPENPGP ) + \
430  sizeofObject( pkcs15infoPtr->openPGPKeyIDlength ) );
431  writeShortInteger( stream, PKCS15_KEYID_OPENPGP, DEFAULT_TAG );
432  status = writeOctetString( stream, pkcs15infoPtr->openPGPKeyID,
433  pkcs15infoPtr->openPGPKeyIDlength,
434  DEFAULT_TAG );
435  }
436 
437  return( status );
438  }
439 
440 /* Write atributes to a buffer */
441 
442 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 6, 7 ) ) \
443 int writeKeyAttributes( OUT_BUFFER( privKeyAttributeMaxLen, \
445  void *privKeyAttributes,
446  IN_LENGTH_SHORT_MIN( 16 ) \
447  const int privKeyAttributeMaxLen,
449  OUT_BUFFER( pubKeyAttributeMaxLen, \
451  void *pubKeyAttributes,
452  IN_LENGTH_SHORT_MIN( 16 ) \
453  const int pubKeyAttributeMaxLen,
455  INOUT PKCS15_INFO *pkcs15infoPtr,
456  IN_HANDLE const CRYPT_HANDLE iCryptContext )
457  {
458  STREAM stream;
459  int commonAttributeSize, commonKeyAttributeSize, keyUsage, status;
460 
461  assert( isWritePtr( privKeyAttributes, privKeyAttributeMaxLen ) );
462  assert( isWritePtr( privKeyAttributeSize, sizeof( int ) ) );
463  assert( isWritePtr( pubKeyAttributes, pubKeyAttributeMaxLen ) );
464  assert( isWritePtr( pubKeyAttributeSize, sizeof( int ) ) );
465  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
466 
467  REQUIRES( privKeyAttributeMaxLen >= 16 && \
468  privKeyAttributeMaxLen < MAX_INTLENGTH_SHORT );
469  REQUIRES( pubKeyAttributeMaxLen >= 16 && \
470  pubKeyAttributeMaxLen < MAX_INTLENGTH_SHORT );
471  REQUIRES( isHandleRangeValid( iCryptContext ) );
472 
473  /* Clear return values */
474  memset( privKeyAttributes, 0, min( 16, privKeyAttributeMaxLen ) );
475  memset( pubKeyAttributes, 0, min( 16, pubKeyAttributeMaxLen ) );
476  *privKeyAttributeSize = *pubKeyAttributeSize = 0;
477 
478  /* Get ID information from the context */
479  status = getKeyIDs( pkcs15infoPtr, iCryptContext );
480  if( cryptStatusError( status ) )
481  return( status );
482 
483  /* Try and get the validity information. This isn't used at this point
484  but may be needed before it's set in the certificate write code, for
485  example when adding two certificates that differ only in validity
486  period to a keyset. Since we could be adding a raw key we ignore any
487  return code */
488  ( void ) getValidityInfo( pkcs15infoPtr, iCryptContext );
489 
490  /* Figure out the PKCS #15 key usage flags. The action flags for an
491  object can change over time under the influence of another object.
492  For example when a raw private key is initially written and unless
493  something else has told it otherwise it'll have all permissible
494  actions enabled. When a certificate for the key is later added the
495  permissible actions for the key may be constrained by the certificate
496  so the private key flags will change when the object is re-written to
497  the keyset */
498  keyUsage = getKeyUsageFlags( iCryptContext,
499  pkcs15infoPtr->privKeyUsage );
500  if( keyUsage <= 0 )
501  return( CRYPT_ERROR_PERMISSION ); /* No easy way to report this one */
502 
503  /* Determine how big the private key attribute collections will be */
504  commonAttributeSize = ( int) sizeofObject( pkcs15infoPtr->labelLength );
505  commonKeyAttributeSize = ( int ) sizeofObject( pkcs15infoPtr->iDlength ) + \
506  sizeofBitString( keyUsage ) + \
507  sizeofBitString( KEYATTR_ACCESS_PRIVATE );
508  if( pkcs15infoPtr->validFrom > MIN_TIME_VALUE )
509  commonKeyAttributeSize += sizeofGeneralizedTime();
510  if( pkcs15infoPtr->validTo > MIN_TIME_VALUE )
511  commonKeyAttributeSize += sizeofGeneralizedTime();
512 
513  /* Write the private key attributes */
514  sMemOpen( &stream, privKeyAttributes, privKeyAttributeMaxLen );
515  writeSequence( &stream, commonAttributeSize );
516  writeCharacterString( &stream, ( BYTE * ) pkcs15infoPtr->label,
517  pkcs15infoPtr->labelLength, BER_STRING_UTF8 );
518  writeSequence( &stream, commonKeyAttributeSize );
519  writeOctetString( &stream, pkcs15infoPtr->iD, pkcs15infoPtr->iDlength,
520  DEFAULT_TAG );
521  writeBitString( &stream, keyUsage, DEFAULT_TAG );
522  status = writeBitString( &stream, KEYATTR_ACCESS_PRIVATE, DEFAULT_TAG );
523  if( pkcs15infoPtr->validFrom > MIN_TIME_VALUE )
524  status = writeGeneralizedTime( &stream, pkcs15infoPtr->validFrom,
525  DEFAULT_TAG );
526  if( pkcs15infoPtr->validTo > MIN_TIME_VALUE )
527  status = writeGeneralizedTime( &stream, pkcs15infoPtr->validTo,
528  CTAG_KA_VALIDTO );
529  if( cryptStatusOK( status ) )
530  *privKeyAttributeSize = stell( &stream );
531  sMemDisconnect( &stream );
532  ENSURES( cryptStatusOK( status ) );
533  pkcs15infoPtr->privKeyUsage = keyUsage; /* Update stored usage information */
534 
535  /* Determine how big the public key attribute collections will be */
536  keyUsage &= PUBKEY_USAGE_MASK;
537  commonKeyAttributeSize = ( int ) sizeofObject( pkcs15infoPtr->iDlength ) + \
538  sizeofBitString( keyUsage ) + \
539  sizeofBitString( KEYATTR_ACCESS_PUBLIC );
540  if( pkcs15infoPtr->validFrom > MIN_TIME_VALUE )
541  commonKeyAttributeSize += sizeofGeneralizedTime();
542  if( pkcs15infoPtr->validTo > MIN_TIME_VALUE )
543  commonKeyAttributeSize += sizeofGeneralizedTime();
544 
545  /* Write the public key attributes */
546  sMemOpen( &stream, pubKeyAttributes, pubKeyAttributeMaxLen );
547  writeSequence( &stream, commonAttributeSize );
548  writeCharacterString( &stream, ( BYTE * ) pkcs15infoPtr->label,
549  pkcs15infoPtr->labelLength, BER_STRING_UTF8 );
550  writeSequence( &stream, commonKeyAttributeSize );
551  writeOctetString( &stream, pkcs15infoPtr->iD, pkcs15infoPtr->iDlength,
552  DEFAULT_TAG );
553  writeBitString( &stream, keyUsage, DEFAULT_TAG );
554  status = writeBitString( &stream, KEYATTR_ACCESS_PUBLIC, DEFAULT_TAG );
555  if( pkcs15infoPtr->validFrom > MIN_TIME_VALUE )
556  status = writeGeneralizedTime( &stream, pkcs15infoPtr->validFrom,
557  DEFAULT_TAG );
558  if( pkcs15infoPtr->validTo > MIN_TIME_VALUE )
559  status = writeGeneralizedTime( &stream, pkcs15infoPtr->validTo,
560  CTAG_KA_VALIDTO );
561  if( cryptStatusOK( status ) )
562  *pubKeyAttributeSize = stell( &stream );
563  sMemDisconnect( &stream );
564  ENSURES( cryptStatusOK( status ) );
565  pkcs15infoPtr->pubKeyUsage = keyUsage; /* Update stored usage information */
566 
567  return( CRYPT_OK );
568  }
569 
570 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
571 int writeCertAttributes( OUT_BUFFER( certAttributeMaxLen, *certAttributeSize ) \
572  void *certAttributes,
573  IN_LENGTH_SHORT_MIN( 16 ) const int certAttributeMaxLen,
575  INOUT PKCS15_INFO *pkcs15infoPtr,
576  IN_HANDLE const CRYPT_HANDLE iCryptCert )
577  {
578  STREAM stream;
579  BOOLEAN trustedImplicit;
580  int commonAttributeSize, commonCertAttributeSize;
581  int keyIdentifierDataSize, trustedUsageSize;
582  int isCA, trustedUsage, status;
583 
584  assert( isWritePtr( certAttributes, certAttributeMaxLen ) );
585  assert( isWritePtr( certAttributeSize, sizeof( int ) ) );
586  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
587 
588  REQUIRES( certAttributeMaxLen >= 16 && \
589  certAttributeMaxLen < MAX_INTLENGTH_SHORT );
590  REQUIRES( isHandleRangeValid( iCryptCert ) );
591 
592  /* Clear return values */
593  memset( certAttributes, 0, min( 16, certAttributeMaxLen ) );
594  *certAttributeSize = 0;
595 
596  /* Get ID information from the certificate */
597  status = getCertIDs( pkcs15infoPtr, iCryptCert, &isCA,
598  &trustedImplicit, &trustedUsage );
599  if( cryptStatusError( status ) )
600  return( status );
601 
602  /* At this point we could create a pseudo-label by reading the
603  CRYPT_IATTRIBUTE_HOLDERNAME attribute, however label-less items will
604  only occur when adding a standalone (i.e. trusted, implicitly-
605  handled) certificate. If we were to set labels for these then the
606  keyset would end up acting as a general-purpose certificate store
607  which it isn't meant to be, so we always leave implicitly handled
608  certificates label-less */
609 
610  /* Determine how big the attribute collection will be */
611  trustedUsageSize = ( trustedUsage != CRYPT_UNUSED ) ? \
612  sizeofBitString( trustedUsage ) : 0;
613  keyIdentifierDataSize = sizeofObjectIDs( pkcs15infoPtr );
614  commonAttributeSize = ( pkcs15infoPtr->labelLength > 0 ) ? \
615  ( int) sizeofObject( pkcs15infoPtr->labelLength ) : 0;
616  commonCertAttributeSize = ( int ) \
617  sizeofObject( pkcs15infoPtr->iDlength ) + \
618  ( isCA ? sizeofBoolean() : 0 ) + \
619  ( ( trustedUsage != CRYPT_UNUSED ) ? \
620  sizeofObject( trustedUsageSize ) : 0 ) + \
621  sizeofObject( keyIdentifierDataSize ) + \
622  ( trustedImplicit ? sizeofBoolean() : 0 ) + \
624 
625  /* Write the certificate attributes */
626  sMemOpen( &stream, certAttributes, certAttributeMaxLen );
627  writeSequence( &stream, commonAttributeSize );
628  if( commonAttributeSize > 0 )
629  writeCharacterString( &stream, pkcs15infoPtr->label,
630  pkcs15infoPtr->labelLength, BER_STRING_UTF8 );
631  writeSequence( &stream, commonCertAttributeSize );
632  writeOctetString( &stream, pkcs15infoPtr->iD, pkcs15infoPtr->iDlength,
633  DEFAULT_TAG );
634  if( isCA )
635  writeBoolean( &stream, TRUE, DEFAULT_TAG );
636  if( trustedUsage != CRYPT_UNUSED )
637  {
638  writeConstructed( &stream, trustedUsageSize, CTAG_CA_TRUSTED_USAGE );
639  writeBitString( &stream, trustedUsage, DEFAULT_TAG );
640  }
641  status = writeObjectIDs( &stream, pkcs15infoPtr, keyIdentifierDataSize,
643  ENSURES( cryptStatusOK( status ) );
644  if( trustedImplicit )
645  writeBoolean( &stream, TRUE, CTAG_CA_TRUSTED_IMPLICIT );
646  writeGeneralizedTime( &stream, pkcs15infoPtr->validFrom, DEFAULT_TAG );
647  status = writeGeneralizedTime( &stream, pkcs15infoPtr->validTo,
648  CTAG_CA_VALIDTO );
649  if( cryptStatusOK( status ) )
650  *certAttributeSize = stell( &stream );
651  sMemDisconnect( &stream );
652  ENSURES( cryptStatusOK( status ) );
653 
654  return( CRYPT_OK );
655  }
656 #endif /* USE_PKCS15 */