cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
key_wr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Public/Private Key Write Routines *
4 * Copyright Peter Gutmann 1992-2009 *
5 * *
6 ****************************************************************************/
7 
8 #include <stdio.h>
9 #define PKC_CONTEXT /* Indicate that we're working with PKC contexts */
10 #if defined( INC_ALL )
11  #include "context.h"
12  #include "asn1.h"
13  #include "asn1_ext.h"
14  #include "misc_rw.h"
15  #include "pgp.h"
16 #else
17  #include "context/context.h"
18  #include "enc_dec/asn1.h"
19  #include "enc_dec/asn1_ext.h"
20  #include "enc_dec/misc_rw.h"
21  #include "misc/pgp.h"
22 #endif /* Compiler-specific includes */
23 
24 /* Although there is a fair amount of commonality between public and private-
25  key functions, we keep them distinct to enforce red/black separation.
26 
27  The DLP algorithms split the key components over the information in the
28  AlgorithmIdentifier and the actual public/private key components, with the
29  (p, q, g) set classed as domain parameters and included in the
30  AlgorithmIdentifier and y being the actual key.
31 
32  params = SEQ {
33  p INTEGER,
34  q INTEGER, -- q for DSA
35  g INTEGER, -- g for DSA
36  j INTEGER OPTIONAL, -- X9.42 only
37  validationParams [...] -- X9.42 only
38  }
39 
40  key = y INTEGER -- g^x mod p
41 
42  For peculiar historical reasons (copying errors and the use of obsolete
43  drafts as reference material) the X9.42 interpretation used in PKIX
44  reverses the second two parameters from FIPS 186 (so it uses p, g, q
45  instead of p, q, g), so when we read/write the parameter information we
46  have to switch the order in which we read the values if the algorithm
47  isn't DSA */
48 
49 #define hasReversedParams( cryptAlgo ) \
50  ( ( cryptAlgo ) == CRYPT_ALGO_DH || \
51  ( cryptAlgo ) == CRYPT_ALGO_ELGAMAL )
52 
53 /* Prototypes for functions in key_rd.c */
54 
56 int getECCOidTbl( OUT const OID_INFO **oidTblPtr,
57  OUT_INT_Z int *noOidTblEntries );
58 
59 #ifdef USE_PKC
60 
61 /****************************************************************************
62 * *
63 * Utility Routines *
64 * *
65 ****************************************************************************/
66 
67 #if defined( USE_SSH )
68 
69 /* Write a bignum as a fixed-length value, needed by several encoding
70  types and formats */
71 
72 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
73 static int writeFixedBignum( INOUT STREAM *stream, const BIGNUM *bignum,
74  IN_LENGTH_SHORT_MIN( 20 ) const int fixedSize )
75  {
77  int bnLength, noZeroes, i, status;
78 
79  assert( isWritePtr( stream, sizeof( STREAM ) ) );
80  assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );
81 
82  REQUIRES( fixedSize >= 20 && fixedSize <= CRYPT_MAX_PKCSIZE );
83 
84  /* Extract the bignum data and get its length */
85  status = exportBignum( buffer, CRYPT_MAX_PKCSIZE, &bnLength, bignum );
86  ENSURES( cryptStatusOK( status ) );
87  noZeroes = fixedSize - bnLength;
88  REQUIRES( noZeroes >= 0 && noZeroes < fixedSize );
89 
90  /* Write the leading zeroes followed by the bignum value */
91  for( i = 0; i < noZeroes; i++ )
92  sputc( stream, 0 );
93  status = swrite( stream, buffer, bnLength );
94  zeroise( buffer, CRYPT_MAX_PKCSIZE );
95 
96  return( status );
97  }
98 #endif /* USE_SSH */
99 
100 /****************************************************************************
101 * *
102 * Write Public Keys *
103 * *
104 ****************************************************************************/
105 
106 /* Write X.509 SubjectPublicKeyInfo public keys */
107 
108 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
109 static int writeRsaSubjectPublicKey( INOUT STREAM *stream,
111  {
112  const PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
113  const int length = sizeofBignum( &rsaKey->rsaParam_n ) + \
114  sizeofBignum( &rsaKey->rsaParam_e );
115 
116  assert( isWritePtr( stream, sizeof( STREAM ) ) );
117  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
118 
119  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
120  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );
121 
122  /* Write the SubjectPublicKeyInfo header field (the +1 is for the
123  bitstring) */
124  writeSequence( stream, sizeofAlgoID( CRYPT_ALGO_RSA ) + \
125  ( int ) sizeofObject( \
126  sizeofObject( length ) + 1 ) );
127  writeAlgoID( stream, CRYPT_ALGO_RSA );
128 
129  /* Write the BIT STRING wrapper and the PKC information */
130  writeBitStringHole( stream, ( int ) sizeofObject( length ),
131  DEFAULT_TAG );
132  writeSequence( stream, length );
133  writeBignum( stream, &rsaKey->rsaParam_n );
134  return( writeBignum( stream, &rsaKey->rsaParam_e ) );
135  }
136 
137 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
138 static int writeDlpSubjectPublicKey( INOUT STREAM *stream,
139  const CONTEXT_INFO *contextInfoPtr )
140  {
141  const CRYPT_ALGO_TYPE cryptAlgo = contextInfoPtr->capabilityInfo->cryptAlgo;
142  const PKC_INFO *dlpKey = contextInfoPtr->ctxPKC;
143  const int parameterSize = ( int ) sizeofObject( \
144  sizeofBignum( &dlpKey->dlpParam_p ) + \
145  sizeofBignum( &dlpKey->dlpParam_q ) + \
146  sizeofBignum( &dlpKey->dlpParam_g ) );
147  const int componentSize = sizeofBignum( &dlpKey->dlpParam_y );
148  int totalSize;
149 
150  assert( isWritePtr( stream, sizeof( STREAM ) ) );
151  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
152 
153  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
154  ( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DH || \
155  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DSA || \
156  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ELGAMAL ) );
157 
158  /* If it's an Elgamal key created by PGP or a DH key from SSL/SSH then
159  the q parameter isn't present so we can't write the key in this format */
160  if( BN_is_zero( &dlpKey->dlpParam_q ) )
161  {
162  DEBUG_DIAG(( "Can't write Elgamal key due to missing q parameter" ));
163  assert( DEBUG_WARN );
164  return( CRYPT_ERROR_NOTAVAIL );
165  }
166 
167  /* Determine the size of the AlgorithmIdentifier and the BIT STRING-
168  encapsulated public-key data (the +1 is for the bitstring) */
169  totalSize = sizeofAlgoIDex( cryptAlgo, CRYPT_ALGO_NONE, parameterSize ) + \
170  ( int ) sizeofObject( componentSize + 1 );
171 
172  /* Write the SubjectPublicKeyInfo header field */
173  writeSequence( stream, totalSize );
174  writeAlgoIDparam( stream, cryptAlgo, parameterSize );
175 
176  /* Write the parameter data */
177  writeSequence( stream, sizeofBignum( &dlpKey->dlpParam_p ) + \
178  sizeofBignum( &dlpKey->dlpParam_q ) + \
179  sizeofBignum( &dlpKey->dlpParam_g ) );
180  writeBignum( stream, &dlpKey->dlpParam_p );
181  if( hasReversedParams( cryptAlgo ) )
182  {
183  writeBignum( stream, &dlpKey->dlpParam_g );
184  writeBignum( stream, &dlpKey->dlpParam_q );
185  }
186  else
187  {
188  writeBignum( stream, &dlpKey->dlpParam_q );
189  writeBignum( stream, &dlpKey->dlpParam_g );
190  }
191 
192  /* Write the BIT STRING wrapper and the PKC information */
193  writeBitStringHole( stream, componentSize, DEFAULT_TAG );
194  return( writeBignum( stream, &dlpKey->dlpParam_y ) );
195  }
196 
197 #if defined( USE_ECDH ) || defined( USE_ECDSA )
198 
199 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
200 static int writeEccSubjectPublicKey( INOUT STREAM *stream,
201  const CONTEXT_INFO *contextInfoPtr )
202  {
203  const PKC_INFO *eccKey = contextInfoPtr->ctxPKC;
204  const OID_INFO *oidTbl;
205  const BYTE *oid = NULL;
206  BYTE buffer[ MAX_PKCSIZE_ECCPOINT + 8 ];
207  int oidTblSize, fieldSize = DUMMY_INIT, encodedPointSize, totalSize;
208  int i, status;
209 
210  assert( isWritePtr( stream, sizeof( STREAM ) ) );
211  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
212 
213  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
214  ( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ECDSA || \
215  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ECDH ) );
216 
217  /* Get the information that we'll need to encode the key. Note that
218  this assumes that we'll be using a known (named) curve rather than
219  arbitrary curve parameters, which has been enforced by the higher-
220  level code */
221  status = getECCOidTbl( &oidTbl, &oidTblSize );
222  if( cryptStatusOK( status ) )
223  status = getECCFieldSize( eccKey->curveType, &fieldSize );
224  if( cryptStatusError( status ) )
225  return( status );
226  for( i = 0; i < oidTblSize && oidTbl[ i ].oid != NULL; i++ )
227  {
228  if( oidTbl[ i ].selectionID == eccKey->curveType )
229  {
230  oid = oidTbl[ i ].oid;
231  break;
232  }
233  }
234  ENSURES( i < oidTblSize );
235  ENSURES( oid != NULL );
236 
237  /* Get the encoded point data */
238  status = exportECCPoint( buffer, MAX_PKCSIZE_ECCPOINT, &encodedPointSize,
239  &eccKey->eccParam_qx, &eccKey->eccParam_qy,
240  fieldSize );
241  if( cryptStatusError( status ) )
242  return( status );
243 
244  /* Determine the size of the AlgorithmIdentifier and the BIT STRING-
245  encapsulated public-key data (the final +1 is for the bitstring),
246  ECC algorithms are a bit strange because there's no specific type of
247  "ECDSA key" or "ECDH key" or whatever, just a generic "ECC key", so
248  if we're given an ECDH key we write it as a generic ECC key, denoted
249  using the generic identifier CRYPT_ALGO_ECDSA */
251  sizeofOID( oid ) ) + \
252  ( int ) sizeofObject( encodedPointSize + 1 );
253 
254  /* Write the SubjectPublicKeyInfo header field */
255  writeSequence( stream, totalSize );
256  writeAlgoIDparam( stream, CRYPT_ALGO_ECDSA, sizeofOID( oid ) );
257 
258  /* Write the parameter data */
259  writeOID( stream, oid );
260 
261  /* Write the BIT STRING wrapper and the PKC information */
262  writeBitStringHole( stream, encodedPointSize, DEFAULT_TAG );
263  status = swrite( stream, buffer, encodedPointSize );
264  zeroise( buffer, MAX_PKCSIZE_ECCPOINT );
265  return( status );
266  }
267 #endif /* USE_ECDH || USE_ECDSA */
268 
269 #ifdef USE_SSH1
270 
271 /* Write SSHv1 public keys:
272 
273  uint32 keysize_bits
274  mpint exponent
275  mpint modulus */
276 
277 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
278 static int writeSsh1RsaPublicKey( INOUT STREAM *stream,
279  const CONTEXT_INFO *contextInfoPtr )
280  {
281  const PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
282 
283  assert( isWritePtr( stream, sizeof( STREAM ) ) );
284  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
285 
286  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
287  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );
288 
289  writeUint32( stream, BN_num_bits( &rsaKey->rsaParam_n ) );
290  writeBignumInteger16Ubits( stream, &rsaKey->rsaParam_e );
291  return( writeBignumInteger16Ubits( stream, &rsaKey->rsaParam_n ) );
292  }
293 #endif /* USE_SSH1 */
294 
295 #ifdef USE_SSH
296 
297 /* Write SSHv2 public keys:
298 
299  RSA/DSA:
300 
301  string [ server key/certificate ]
302  string "ssh-rsa" "ssh-dss"
303  mpint e p
304  mpint n q
305  mpint g
306  mpint y
307 
308  ECDSA:
309 
310  string [ server key/certificate ]
311  string "ecdsa-sha2-*"
312  string "*" -- The "*" portion from the above field
313  string Q */
314 
315 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
316 static int writeSshRsaPublicKey( INOUT STREAM *stream,
317  const CONTEXT_INFO *contextInfoPtr )
318  {
319  const PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
320 
321  assert( isWritePtr( stream, sizeof( STREAM ) ) );
322  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
323 
324  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
325  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );
326 
327  writeUint32( stream, sizeofString32( "ssh-rsa", 7 ) + \
328  sizeofBignumInteger32( &rsaKey->rsaParam_e ) + \
329  sizeofBignumInteger32( &rsaKey->rsaParam_n ) );
330  writeString32( stream, "ssh-rsa", 7 );
331  writeBignumInteger32( stream, &rsaKey->rsaParam_e );
332  return( writeBignumInteger32( stream, &rsaKey->rsaParam_n ) );
333  }
334 
335 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
336 static int writeSshDlpPublicKey( INOUT STREAM *stream,
337  const CONTEXT_INFO *contextInfoPtr )
338  {
339  const PKC_INFO *dsaKey = contextInfoPtr->ctxPKC;
340 
341  assert( isWritePtr( stream, sizeof( STREAM ) ) );
342  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
343 
344  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
345  ( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DH || \
346  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DSA ) );
347 
348  /* SSHv2 uses PKCS #3 rather than X9.42-style DH keys so we have to
349  treat this algorithm type specially */
350  if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DH )
351  {
352  writeUint32( stream, sizeofString32( "ssh-dh", 6 ) + \
353  sizeofBignumInteger32( &dsaKey->dlpParam_p ) + \
354  sizeofBignumInteger32( &dsaKey->dlpParam_g ) );
355  writeString32( stream, "ssh-dh", 6 );
356  writeBignumInteger32( stream, &dsaKey->dlpParam_p );
357  return( writeBignumInteger32( stream, &dsaKey->dlpParam_g ) );
358  }
359 
360  writeUint32( stream, sizeofString32( "ssh-dss", 7 ) + \
361  sizeofBignumInteger32( &dsaKey->dlpParam_p ) + \
362  sizeofBignumInteger32( &dsaKey->dlpParam_q ) + \
363  sizeofBignumInteger32( &dsaKey->dlpParam_g ) + \
364  sizeofBignumInteger32( &dsaKey->dlpParam_y ) );
365  writeString32( stream, "ssh-dss", 7 );
366  writeBignumInteger32( stream, &dsaKey->dlpParam_p );
367  writeBignumInteger32( stream, &dsaKey->dlpParam_q );
368  writeBignumInteger32( stream, &dsaKey->dlpParam_g );
369  return( writeBignumInteger32( stream, &dsaKey->dlpParam_y ) );
370  }
371 
372 #if defined( USE_ECDH ) || defined( USE_ECDSA )
373 
374 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
375 static int writeSshEccPublicKey( INOUT STREAM *stream,
376  const CONTEXT_INFO *contextInfoPtr )
377  {
378  const PKC_INFO *eccKey = contextInfoPtr->ctxPKC;
379  const char *algoName, *paramName;
380  BYTE buffer[ MAX_PKCSIZE_ECCPOINT + 8 ];
381  int fieldSize, encodedPointSize = DUMMY_INIT;
382  int algoNameLen, paramNameLen, status;
383 
384  assert( isWritePtr( stream, sizeof( STREAM ) ) );
385  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
386 
387  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
388  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ECDSA );
389 
390  /* Get the string form of the curve parameters */
391  switch( eccKey->curveType )
392  {
393  case CRYPT_ECCCURVE_P256:
394  algoName = "ecdsa-sha2-nistp256";
395  algoNameLen = 19;
396  paramName = "nistp256";
397  paramNameLen = 8;
398  break;
399 
400  case CRYPT_ECCCURVE_P384:
401  algoName = "ecdsa-sha2-nistp384";
402  algoNameLen = 19;
403  paramName = "nistp384";
404  paramNameLen = 8;
405  break;
406 
407  case CRYPT_ECCCURVE_P521:
408  algoName = "ecdsa-sha2-nistp521";
409  algoNameLen = 19;
410  paramName = "nistp521";
411  paramNameLen = 8;
412  break;
413 
414  default:
415  retIntError();
416  }
417 
418  /* Get the information that we'll need to encode the key and the encoded
419  point data. Note that this assumes that we'll be using a known
420  (named) curve rather than arbitrary curve parameters, which has been
421  enforced by the higher-level code */
422  status = getECCFieldSize( eccKey->curveType, &fieldSize );
423  if( cryptStatusOK( status ) )
424  {
425  status = exportECCPoint( buffer, MAX_PKCSIZE_ECCPOINT,
426  &encodedPointSize, &eccKey->eccParam_qx,
427  &eccKey->eccParam_qy, fieldSize );
428  }
429  if( cryptStatusError( status ) )
430  return( status );
431 
432  /* Write the PKC information */
433  writeUint32( stream, sizeofString32( algoName, algoNameLen ) + \
434  sizeofString32( paramName, paramNameLen ) + \
435  sizeofString32( buffer, encodedPointSize ) );
436  writeString32( stream, algoName, algoNameLen );
437  writeString32( stream, paramName, paramNameLen );
438  status = writeString32( stream, buffer, encodedPointSize );
439  zeroise( buffer, MAX_PKCSIZE_ECCPOINT );
440  return( status );
441  }
442 #endif /* USE_ECDH || USE_ECDSA */
443 
444 #endif /* USE_SSH */
445 
446 #ifdef USE_SSL
447 
448 /* Write SSL public keys:
449 
450  DH:
451  uint16 dh_pLen
452  byte[] dh_p
453  uint16 dh_gLen
454  byte[] dh_g
455  [ uint16 dh_YsLen ]
456  [ byte[] dh_Ys ]
457 
458  ECDH:
459  byte curveType
460  uint16 namedCurve
461  [ uint8 ecPointLen -- NB uint8 not uint16 ]
462  [ byte[] ecPoint ]
463 
464  The DH y value is nominally attached to the DH p and g values but isn't
465  processed at this level since this is a pure PKCS #3 DH key and not a
466  generic DLP key. The same holds for the ECDH Q value */
467 
468 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
469 static int writeSslDlpPublicKey( INOUT STREAM *stream,
470  const CONTEXT_INFO *contextInfoPtr )
471  {
472  const PKC_INFO *dhKey = contextInfoPtr->ctxPKC;
473 
474  assert( isWritePtr( stream, sizeof( STREAM ) ) );
475  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
476 
477  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
478  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DH );
479 
480  writeBignumInteger16U( stream, &dhKey->dlpParam_p );
481  return( writeBignumInteger16U( stream, &dhKey->dlpParam_g ) );
482  }
483 
484 #if defined( USE_ECDH ) || defined( USE_ECDSA )
485 
486 static const MAP_TABLE sslCurveInfo[] = {
487  { CRYPT_ECCCURVE_P192, 19 },
488  { CRYPT_ECCCURVE_P224, 21 },
489  { CRYPT_ECCCURVE_P256, 23 },
490  { CRYPT_ECCCURVE_P384, 24 },
491  { CRYPT_ECCCURVE_P521, 25 },
492  { CRYPT_ERROR, 0 },
493  { CRYPT_ERROR, 0 }
494  };
495 
496 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
497 static int getEccSslInfoTbl( OUT const MAP_TABLE **sslInfoTblPtr,
498  OUT_INT_Z int *noSslInfoTblEntries )
499  {
500  assert( isReadPtr( sslInfoTblPtr, sizeof( MAP_TABLE * ) ) );
501  assert( isWritePtr( noSslInfoTblEntries, sizeof( int ) ) );
502 
503  *sslInfoTblPtr = sslCurveInfo;
504  *noSslInfoTblEntries = FAILSAFE_ARRAYSIZE( sslCurveInfo, MAP_TABLE );
505 
506  return( CRYPT_OK );
507  }
508 
509 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
510 static int writeSslEccPublicKey( INOUT STREAM *stream,
511  const CONTEXT_INFO *contextInfoPtr )
512  {
513  const PKC_INFO *eccKey = contextInfoPtr->ctxPKC;
514  const MAP_TABLE *sslCurveInfoPtr;
515  int curveID, sslCurveInfoNoEntries, status;
516 
517  assert( isWritePtr( stream, sizeof( STREAM ) ) );
518  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
519 
520  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
521  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ECDH );
522 
523  /* Look up the SSL NamedCurve ID based on the curve ID */
524  status = getEccSslInfoTbl( &sslCurveInfoPtr, &sslCurveInfoNoEntries );
525  if( cryptStatusError( status ) )
526  return( status );
527  status = mapValue( eccKey->curveType, &curveID, sslCurveInfoPtr,
528  sslCurveInfoNoEntries );
529  if( cryptStatusError( status ) )
530  return( status );
531 
532  sputc( stream, 0x03 ); /* NamedCurve */
533  return( writeUint16( stream, curveID ) );
534  }
535 #endif /* USE_ECDH || USE_ECDSA */
536 
537 #endif /* USE_SSL */
538 
539 #ifdef USE_PGP
540 
541 /* Write PGP public keys:
542 
543  byte version
544  uint32 creationTime
545  [ uint16 validity - version 2 or 3 only ]
546  byte RSA DSA Elgamal
547  mpi n p p
548  mpi e q g
549  mpi g y
550  mpi y */
551 
552 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
553 static int writePgpRsaPublicKey( INOUT STREAM *stream,
554  const CONTEXT_INFO *contextInfoPtr )
555  {
556  const PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
557 
558  assert( isWritePtr( stream, sizeof( STREAM ) ) );
559  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
560 
561  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
562  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );
563 
564  sputc( stream, PGP_VERSION_OPENPGP );
565  if( rsaKey->pgpCreationTime < MIN_TIME_VALUE )
566  writeUint32( stream, 0 );
567  else
568  writeUint32Time( stream, rsaKey->pgpCreationTime );
569  sputc( stream, PGP_ALGO_RSA );
570  writeBignumInteger16Ubits( stream, &rsaKey->rsaParam_n );
571  return( writeBignumInteger16Ubits( stream, &rsaKey->rsaParam_e ) );
572  }
573 
574 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
575 static int writePgpDlpPublicKey( INOUT STREAM *stream,
576  const CONTEXT_INFO *contextInfoPtr )
577  {
578  const PKC_INFO *dlpKey = contextInfoPtr->ctxPKC;
579  const CRYPT_ALGO_TYPE cryptAlgo = contextInfoPtr->capabilityInfo->cryptAlgo;
580 
581  assert( isWritePtr( stream, sizeof( STREAM ) ) );
582  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
583 
584  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
585  ( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DSA || \
586  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ELGAMAL ) );
587 
588  sputc( stream, PGP_VERSION_OPENPGP );
589  if( dlpKey->pgpCreationTime < MIN_TIME_VALUE )
590  writeUint32( stream, 0 );
591  else
592  writeUint32Time( stream, dlpKey->pgpCreationTime );
593  sputc( stream, ( cryptAlgo == CRYPT_ALGO_DSA ) ? \
595  writeBignumInteger16Ubits( stream, &dlpKey->dlpParam_p );
596  if( cryptAlgo == CRYPT_ALGO_DSA )
597  writeBignumInteger16Ubits( stream, &dlpKey->dlpParam_q );
598  writeBignumInteger16Ubits( stream, &dlpKey->dlpParam_g );
599  return( writeBignumInteger16Ubits( stream, &dlpKey->dlpParam_y ) );
600  }
601 #endif /* USE_PGP */
602 
603 /* Umbrella public-key write functions */
604 
605 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
606 static int writePublicKeyRsaFunction( INOUT STREAM *stream,
607  const CONTEXT_INFO *contextInfoPtr,
608  IN_ENUM( KEYFORMAT ) \
610  IN_BUFFER( accessKeyLen ) \
611  const char *accessKey,
612  IN_LENGTH_FIXED( 10 ) \
613  const int accessKeyLen )
614  {
615  assert( isWritePtr( stream, sizeof( STREAM ) ) );
616  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
617  assert( isReadPtr( accessKey, accessKeyLen ) );
618 
619  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
620  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );
621  REQUIRES( formatType > KEYFORMAT_NONE && formatType < KEYFORMAT_LAST );
622  REQUIRES( accessKeyLen == 10 );
623 
624  /* Make sure that we really intended to call this function */
625  if( accessKeyLen != 10 || memcmp( accessKey, "public_key", 10 ) )
626  retIntError();
627 
628  switch( formatType )
629  {
630  case KEYFORMAT_CERT:
631  return( writeRsaSubjectPublicKey( stream, contextInfoPtr ) );
632 
633 #ifdef USE_SSH
634  case KEYFORMAT_SSH:
635  return( writeSshRsaPublicKey( stream, contextInfoPtr ) );
636 #endif /* USE_SSH */
637 
638 #ifdef USE_SSH1
639  case KEYFORMAT_SSH1:
640  return( writeSsh1RsaPublicKey( stream, contextInfoPtr ) );
641 #endif /* USE_SSH1 */
642 
643 #ifdef USE_PGP
644  case KEYFORMAT_PGP:
645  return( writePgpRsaPublicKey( stream, contextInfoPtr ) );
646 #endif /* USE_PGP */
647  }
648 
649  retIntError();
650  }
651 
652 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
653 static int writePublicKeyDlpFunction( INOUT STREAM *stream,
654  const CONTEXT_INFO *contextInfoPtr,
655  IN_ENUM( KEYFORMAT ) \
656  const KEYFORMAT_TYPE formatType,
657  IN_BUFFER( accessKeyLen ) \
658  const char *accessKey,
659  IN_LENGTH_FIXED( 10 ) \
660  const int accessKeyLen )
661  {
662  assert( isWritePtr( stream, sizeof( STREAM ) ) );
663  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
664  assert( isReadPtr( accessKey, accessKeyLen ) );
665 
666  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
667  ( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DH || \
668  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DSA || \
669  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ELGAMAL ) );
670  REQUIRES( formatType > KEYFORMAT_NONE && formatType < KEYFORMAT_LAST );
671  REQUIRES( accessKeyLen == 10 );
672 
673  /* Make sure that we really intended to call this function */
674  if( accessKeyLen != 10 || memcmp( accessKey, "public_key", 10 ) )
675  retIntError();
676 
677  switch( formatType )
678  {
679  case KEYFORMAT_CERT:
680  return( writeDlpSubjectPublicKey( stream, contextInfoPtr ) );
681 
682 #ifdef USE_SSH
683  case KEYFORMAT_SSH:
684  return( writeSshDlpPublicKey( stream, contextInfoPtr ) );
685 #endif /* USE_SSH */
686 
687 #ifdef USE_SSL
688  case KEYFORMAT_SSL:
689  return( writeSslDlpPublicKey( stream, contextInfoPtr ) );
690 #endif /* USE_SSL */
691 
692 #ifdef USE_PGP
693  case KEYFORMAT_PGP:
694  return( writePgpDlpPublicKey( stream, contextInfoPtr ) );
695 #endif /* USE_PGP */
696  }
697 
698  retIntError();
699  }
700 
701 #if defined( USE_ECDH ) || defined( USE_ECDSA )
702 
703 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
704 static int writePublicKeyEccFunction( INOUT STREAM *stream,
705  const CONTEXT_INFO *contextInfoPtr,
706  IN_ENUM( KEYFORMAT ) \
707  const KEYFORMAT_TYPE formatType,
708  IN_BUFFER( accessKeyLen ) \
709  const char *accessKey,
710  IN_LENGTH_FIXED( 10 ) \
711  const int accessKeyLen )
712  {
713  assert( isWritePtr( stream, sizeof( STREAM ) ) );
714  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
715  assert( isReadPtr( accessKey, accessKeyLen ) );
716 
717  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
718  ( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ECDSA || \
719  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ECDH ) );
720  REQUIRES( formatType == KEYFORMAT_CERT || formatType == KEYFORMAT_SSL || \
721  formatType == KEYFORMAT_SSH );
722  REQUIRES( accessKeyLen == 10 );
723 
724  /* Make sure that we really intended to call this function */
725  if( accessKeyLen != 10 || memcmp( accessKey, "public_key", 10 ) )
726  retIntError();
727 
728  switch( formatType )
729  {
730  case KEYFORMAT_CERT:
731  return( writeEccSubjectPublicKey( stream, contextInfoPtr ) );
732 
733 #ifdef USE_SSL
734  case KEYFORMAT_SSL:
735  return( writeSslEccPublicKey( stream, contextInfoPtr ) );
736 #endif /* USE_SSL */
737 
738 #ifdef USE_SSH
739  case KEYFORMAT_SSH:
740  return( writeSshEccPublicKey( stream, contextInfoPtr ) );
741 #endif /* USE_SSH */
742  }
743 
744  retIntError();
745  }
746 #endif /* USE_ECDH || USE_ECDSA */
747 
748 /****************************************************************************
749 * *
750 * Write Private Keys *
751 * *
752 ****************************************************************************/
753 
754 /* Write private keys */
755 
756 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
757 static int writeRsaPrivateKey( INOUT STREAM *stream,
758  const CONTEXT_INFO *contextInfoPtr )
759  {
760  const PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
761  int length = sizeofBignum( &rsaKey->rsaParam_p ) + \
762  sizeofBignum( &rsaKey->rsaParam_q );
763 
764  assert( isWritePtr( stream, sizeof( STREAM ) ) );
765  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
766 
767  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
768  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );
769 
770  /* Add the length of any optional components that may be present */
771  if( !BN_is_zero( &rsaKey->rsaParam_exponent1 ) )
772  {
773  length += sizeofBignum( &rsaKey->rsaParam_exponent1 ) + \
774  sizeofBignum( &rsaKey->rsaParam_exponent2 ) + \
775  sizeofBignum( &rsaKey->rsaParam_u );
776  }
777 
778  /* Write the the PKC fields */
779  writeSequence( stream, length );
780  writeBignumTag( stream, &rsaKey->rsaParam_p, 3 );
781  if( BN_is_zero( &rsaKey->rsaParam_exponent1 ) )
782  return( writeBignumTag( stream, &rsaKey->rsaParam_q, 4 ) );
783  writeBignumTag( stream, &rsaKey->rsaParam_q, 4 );
784  writeBignumTag( stream, &rsaKey->rsaParam_exponent1, 5 );
785  writeBignumTag( stream, &rsaKey->rsaParam_exponent2, 6 );
786  return( writeBignumTag( stream, &rsaKey->rsaParam_u, 7 ) );
787  }
788 
789 #ifdef USE_PKCS12
790 
791 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
792 static int writeRsaPrivateKeyOld( INOUT STREAM *stream,
793  const CONTEXT_INFO *contextInfoPtr )
794  {
795  const PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
796  const int length = sizeofShortInteger( 0 ) + \
797  sizeofBignum( &rsaKey->rsaParam_n ) + \
798  sizeofBignum( &rsaKey->rsaParam_e ) + \
799  sizeofBignum( &rsaKey->rsaParam_d ) + \
800  sizeofBignum( &rsaKey->rsaParam_p ) + \
801  sizeofBignum( &rsaKey->rsaParam_q ) + \
802  sizeofBignum( &rsaKey->rsaParam_exponent1 ) + \
803  sizeofBignum( &rsaKey->rsaParam_exponent2 ) + \
804  sizeofBignum( &rsaKey->rsaParam_u );
805 
806  assert( isWritePtr( stream, sizeof( STREAM ) ) );
807  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
808 
809  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
810  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );
811 
812  /* The older format is somewhat restricted in terms of what can be
813  written since all components must be present, even the ones that are
814  never used. If anything is missing we can't write the key since
815  nothing would be able to read it */
816  if( BN_is_zero( &rsaKey->rsaParam_n ) || \
817  BN_is_zero( &rsaKey->rsaParam_d ) || \
818  BN_is_zero( &rsaKey->rsaParam_p ) || \
819  BN_is_zero( &rsaKey->rsaParam_exponent1 ) )
820  return( CRYPT_ERROR_NOTAVAIL );
821 
822  /* Write the the PKC fields */
823  writeSequence( stream, sizeofShortInteger( 0 ) + \
825  ( int ) sizeofObject( \
826  sizeofObject( length ) ) );
827  writeShortInteger( stream, 0, DEFAULT_TAG );
828  writeAlgoID( stream, CRYPT_ALGO_RSA );
829  writeOctetStringHole( stream, ( int ) sizeofObject( length ),
830  DEFAULT_TAG );
831  writeSequence( stream, length );
832  writeShortInteger( stream, 0, DEFAULT_TAG );
833  writeBignum( stream, &rsaKey->rsaParam_n );
834  writeBignum( stream, &rsaKey->rsaParam_e );
835  writeBignum( stream, &rsaKey->rsaParam_d );
836  writeBignum( stream, &rsaKey->rsaParam_p );
837  writeBignum( stream, &rsaKey->rsaParam_q );
838  writeBignum( stream, &rsaKey->rsaParam_exponent1 );
839  writeBignum( stream, &rsaKey->rsaParam_exponent2 );
840  return( writeBignum( stream, &rsaKey->rsaParam_u ) );
841  }
842 #endif /* USE_PKCS12 */
843 
844 /* Umbrella private-key write functions */
845 
846 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
847 static int writePrivateKeyRsaFunction( INOUT STREAM *stream,
848  const CONTEXT_INFO *contextInfoPtr,
849  IN_ENUM( KEYFORMAT ) \
850  const KEYFORMAT_TYPE formatType,
851  IN_BUFFER( accessKeyLen ) \
852  const char *accessKey,
853  IN_LENGTH_FIXED( 11 ) \
854  const int accessKeyLen )
855  {
856  assert( isWritePtr( stream, sizeof( STREAM ) ) );
857  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
858  assert( isReadPtr( accessKey, accessKeyLen ) );
859 
860  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
861  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );
862  REQUIRES( formatType > KEYFORMAT_NONE && formatType < KEYFORMAT_LAST );
863  REQUIRES( accessKeyLen == 11 );
864 
865  /* Make sure that we really intended to call this function */
866  if( accessKeyLen != 11 || memcmp( accessKey, "private_key", 11 ) || \
867  ( formatType != KEYFORMAT_PRIVATE && \
868  formatType != KEYFORMAT_PRIVATE_OLD ) )
869  retIntError();
870 
871  switch( formatType )
872  {
873  case KEYFORMAT_PRIVATE:
874  return( writeRsaPrivateKey( stream, contextInfoPtr ) );
875 
876 #ifdef USE_PKCS12
878  return( writeRsaPrivateKeyOld( stream, contextInfoPtr ) );
879 #endif /* USE_PKCS12 */
880  }
881 
882  retIntError();
883  }
884 
885 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
886 static int writePrivateKeyDlpFunction( INOUT STREAM *stream,
887  const CONTEXT_INFO *contextInfoPtr,
888  IN_ENUM( KEYFORMAT ) \
889  const KEYFORMAT_TYPE formatType,
890  IN_BUFFER( accessKeyLen ) \
891  const char *accessKey,
892  IN_LENGTH_FIXED( 11 ) \
893  const int accessKeyLen )
894  {
895  const PKC_INFO *dlpKey = contextInfoPtr->ctxPKC;
896 
897  assert( isWritePtr( stream, sizeof( STREAM ) ) );
898  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
899  assert( isReadPtr( accessKey, accessKeyLen ) );
900 
901  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
902  ( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DH || \
903  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DSA || \
904  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ELGAMAL ) );
905  REQUIRES( formatType > KEYFORMAT_NONE && formatType < KEYFORMAT_LAST );
906  REQUIRES( accessKeyLen == 11 );
907 
908  /* Make sure that we really intended to call this function */
909  if( accessKeyLen != 11 || memcmp( accessKey, "private_key", 11 ) || \
910  formatType != KEYFORMAT_PRIVATE )
911  retIntError();
912 
913  /* When we're generating a DH key ID only p, q, and g are initialised so
914  we write a special-case zero y value. This is a somewhat ugly side-
915  effect of the odd way in which DH "public keys" work */
916  if( BN_is_zero( &dlpKey->dlpParam_y ) )
917  return( writeShortInteger( stream, 0, DEFAULT_TAG ) );
918 
919  /* Write the key components */
920  return( writeBignum( stream, &dlpKey->dlpParam_x ) );
921  }
922 
923 #if defined( USE_ECDH ) || defined( USE_ECDSA )
924 
925 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
926 static int writePrivateKeyEccFunction( INOUT STREAM *stream,
927  const CONTEXT_INFO *contextInfoPtr,
928  IN_ENUM( KEYFORMAT ) \
929  const KEYFORMAT_TYPE formatType,
930  IN_BUFFER( accessKeyLen ) \
931  const char *accessKey,
932  IN_LENGTH_FIXED( 11 ) \
933  const int accessKeyLen )
934  {
935  const PKC_INFO *eccKey = contextInfoPtr->ctxPKC;
936 
937  assert( isWritePtr( stream, sizeof( STREAM ) ) );
938  assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
939  assert( isReadPtr( accessKey, accessKeyLen ) );
940 
941  REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
942  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ECDSA );
943  REQUIRES( formatType > KEYFORMAT_NONE && formatType < KEYFORMAT_LAST );
944  REQUIRES( accessKeyLen == 11 );
945 
946  /* Make sure that we really intended to call this function */
947  if( accessKeyLen != 11 || memcmp( accessKey, "private_key", 11 ) || \
948  formatType != KEYFORMAT_PRIVATE )
949  retIntError();
950 
951  /* Write the key components */
952  return( writeBignum( stream, &eccKey->eccParam_d ) );
953  }
954 #endif /* USE_ECDH || USE_ECDSA */
955 
956 /****************************************************************************
957 * *
958 * Write Flat Public Key Data *
959 * *
960 ****************************************************************************/
961 
962 /* If the keys are stored in a crypto device rather than being held in the
963  context all that we'll have available are the public components in flat
964  format. The following code writes flat-format public components in the
965  X.509 SubjectPublicKeyInfo format. The parameters are:
966 
967  Algo Comp1 Comp2 Comp3 Comp4
968  ---- ----- ----- ----- -----
969  RSA n e - -
970  DLP p q g y */
971 
972 CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 5, 7 ) ) \
973 int writeFlatPublicKey( OUT_BUFFER_OPT( bufMaxSize, *bufSize ) void *buffer,
974  IN_LENGTH_SHORT_Z const int bufMaxSize,
976  IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
977  IN_BUFFER( component1Length ) const void *component1,
979  IN_BUFFER( component2Length ) const void *component2,
981  IN_BUFFER_OPT( component3Length ) const void *component3,
983  IN_BUFFER_OPT( component4Length ) const void *component4,
985  {
986  STREAM stream;
987  const int comp1Size = sizeofInteger( component1, component1Length );
988  const int comp2Size = sizeofInteger( component2, component2Length );
989  const int comp3Size = ( component3 == NULL ) ? 0 : \
990  sizeofInteger( component3, component3Length );
991  int parameterSize, componentSize, totalSize, status;
992 
993  assert( ( buffer == NULL && bufMaxSize == 0 ) || \
994  isWritePtr( buffer, bufMaxSize ) );
995  assert( isWritePtr( bufSize, sizeof( int ) ) );
996  assert( isReadPtr( component1, component1Length ) );
997  assert( isReadPtr( component2, component2Length ) );
998  assert( component3 == NULL || \
999  isReadPtr( component3, component3Length ) );
1000  assert( component4 == NULL || \
1001  isReadPtr( component4, component4Length ) );
1002 
1003  REQUIRES( ( buffer == NULL && bufMaxSize == 0 ) || \
1004  ( buffer != NULL && \
1005  bufMaxSize > 64 && bufMaxSize < MAX_INTLENGTH_SHORT ) );
1006  REQUIRES( isPkcAlgo( cryptAlgo ) && !isEccAlgo( cryptAlgo ) );
1007  REQUIRES( component1Length >= MIN_PKCSIZE && \
1008  component1Length <= CRYPT_MAX_PKCSIZE );
1009  REQUIRES( component2Length >= 1 && component2Length <= CRYPT_MAX_PKCSIZE );
1010  REQUIRES( ( component3 == NULL && component3Length == 0 ) || \
1011  ( component3 != NULL && \
1012  component3Length >= 1 && component3Length <= CRYPT_MAX_PKCSIZE ) );
1013  REQUIRES( ( component4 == NULL && component4Length == 0 ) || \
1014  ( component4 != NULL && \
1015  component4Length >= 1 && component4Length <= CRYPT_MAX_PKCSIZE ) );
1016 
1017  /* Clear return values */
1018  if( buffer != NULL )
1019  memset( buffer, 0, min( 16, bufMaxSize ) );
1020  *bufSize = 0;
1021 
1022  /* Calculate the size of the algorithm parameters and the public key
1023  components */
1024  switch( cryptAlgo )
1025  {
1026  case CRYPT_ALGO_DH:
1027  case CRYPT_ALGO_DSA:
1028  case CRYPT_ALGO_ELGAMAL:
1029  REQUIRES( component3 != NULL && component4 != NULL );
1030 
1031  parameterSize = ( int ) sizeofObject( comp1Size + comp2Size + \
1032  comp3Size );
1033  componentSize = sizeofInteger( component4, component4Length );
1034  break;
1035 
1036  case CRYPT_ALGO_RSA:
1037  REQUIRES( component3 == NULL && component4 == NULL );
1038 
1039  parameterSize = 0;
1040  componentSize = ( int ) sizeofObject( comp1Size + comp2Size );
1041  break;
1042 
1043  default:
1044  retIntError();
1045  }
1046 
1047  /* Determine the size of the AlgorithmIdentifier and the BIT STRING-
1048  encapsulated public-key data (the +1 is for the bitstring) */
1049  status = totalSize = sizeofAlgoIDex( cryptAlgo, CRYPT_ALGO_NONE, \
1050  parameterSize );
1051  if( cryptStatusError( status ) )
1052  return( status );
1053  totalSize += ( int ) sizeofObject( componentSize + 1 );
1054  if( buffer == NULL )
1055  {
1056  /* It's a size-check call, return the overall size */
1057  *bufSize = ( int ) sizeofObject( totalSize );
1058 
1059  return( CRYPT_OK );
1060  }
1061 
1062  sMemOpen( &stream, buffer, bufMaxSize );
1063 
1064  /* Write the SubjectPublicKeyInfo header field */
1065  writeSequence( &stream, totalSize );
1066  writeAlgoIDparam( &stream, cryptAlgo, parameterSize );
1067 
1068  /* Write the parameter data if necessary */
1069  if( isDlpAlgo( cryptAlgo ) )
1070  {
1071  writeSequence( &stream, comp1Size + comp2Size + comp3Size );
1072  writeInteger( &stream, component1, component1Length, DEFAULT_TAG );
1073  if( hasReversedParams( cryptAlgo ) )
1074  {
1075  writeInteger( &stream, component3, component3Length, DEFAULT_TAG );
1076  writeInteger( &stream, component2, component2Length, DEFAULT_TAG );
1077  }
1078  else
1079  {
1080  writeInteger( &stream, component2, component2Length, DEFAULT_TAG );
1081  writeInteger( &stream, component3, component3Length, DEFAULT_TAG );
1082  }
1083  }
1084 
1085  /* Write the BIT STRING wrapper and the PKC information */
1086  writeBitStringHole( &stream, componentSize, DEFAULT_TAG );
1087  if( cryptAlgo == CRYPT_ALGO_RSA )
1088  {
1089  writeSequence( &stream, comp1Size + comp2Size );
1090  writeInteger( &stream, component1, component1Length, DEFAULT_TAG );
1091  status = writeInteger( &stream, component2, component2Length,
1092  DEFAULT_TAG );
1093  }
1094  else
1095  {
1096  status = writeInteger( &stream, component4, component4Length,
1097  DEFAULT_TAG );
1098  }
1099  if( cryptStatusOK( status ) )
1100  *bufSize = stell( &stream );
1101 
1102  /* Clean up */
1103  sMemDisconnect( &stream );
1104  return( status );
1105  }
1106 
1107 /****************************************************************************
1108 * *
1109 * Write DL Values *
1110 * *
1111 ****************************************************************************/
1112 
1113 /* Unlike the simpler RSA PKC, DL-based PKCs produce a pair of values that
1114  need to be encoded as structured data. The following two functions
1115  perform this en/decoding. SSH assumes that DLP values are two fixed-size
1116  blocks of 20 bytes so we can't use the normal read/write routines to
1117  handle these values */
1118 
1119 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 5 ) ) \
1120 static int encodeDLValuesFunction( OUT_BUFFER( bufMaxSize, \
1121  *bufSize ) BYTE *buffer,
1122  IN_LENGTH_SHORT_MIN( 20 + 20 ) \
1123  const int bufMaxSize,
1124  OUT_LENGTH_SHORT_Z int *bufSize,
1125  const BIGNUM *value1,
1126  const BIGNUM *value2,
1127  IN_ENUM( CRYPT_FORMAT ) \
1128  const CRYPT_FORMAT_TYPE formatType )
1129  {
1130  STREAM stream;
1131  int length = DUMMY_INIT, status;
1132 
1133  assert( isWritePtr( buffer, bufMaxSize ) );
1134  assert( isWritePtr( bufSize, sizeof( int ) ) );
1135  assert( isReadPtr( value1, sizeof( BIGNUM ) ) );
1136  assert( isReadPtr( value2, sizeof( BIGNUM ) ) );
1137 
1138  REQUIRES( bufMaxSize >= 40 && bufMaxSize < MAX_INTLENGTH_SHORT );
1139  REQUIRES( formatType > CRYPT_FORMAT_NONE && \
1140  formatType < CRYPT_FORMAT_LAST );
1141 
1142  /* Clear return values */
1143  memset( buffer, 0, min( 16, bufMaxSize ) );
1144  *bufSize = 0;
1145 
1146  sMemOpen( &stream, buffer, bufMaxSize );
1147 
1148  /* Write the DL components to the buffer */
1149  switch( formatType )
1150  {
1151  case CRYPT_FORMAT_CRYPTLIB:
1152  writeSequence( &stream, sizeofBignum( value1 ) + \
1153  sizeofBignum( value2 ) );
1154  writeBignum( &stream, value1 );
1155  status = writeBignum( &stream, value2 );
1156  break;
1157 
1158 #ifdef USE_PGP
1159  case CRYPT_FORMAT_PGP:
1160  writeBignumInteger16Ubits( &stream, value1 );
1161  status = writeBignumInteger16Ubits( &stream, value2 );
1162  break;
1163 #endif /* USE_PGP */
1164 
1165 #ifdef USE_SSH
1166  case CRYPT_IFORMAT_SSH:
1167  /* SSH uses an awkward and horribly inflexible fixed format with
1168  each of the nominally 160-bit DLP values at fixed positions
1169  in a 2 x 20-byte buffer, so we have to write the bignums as
1170  fixed-size value */
1171  status = writeFixedBignum( &stream, value1, 20 );
1172  if( cryptStatusOK( status ) )
1173  status = writeFixedBignum( &stream, value2, 20 );
1174  break;
1175 #endif /* USE_SSH */
1176 
1177  default:
1178  retIntError();
1179  }
1180  if( cryptStatusOK( status ) )
1181  length = stell( &stream );
1182  sMemDisconnect( &stream );
1183  if( cryptStatusError( status ) )
1184  return( status );
1185  *bufSize = length;
1186 
1187  return( CRYPT_OK );
1188  }
1189 
1190 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 5 ) ) \
1191 static int encodeECDLValuesFunction( OUT_BUFFER( bufMaxSize, \
1192  *bufSize ) BYTE *buffer,
1193  IN_LENGTH_SHORT_MIN( 20 + 20 ) \
1194  const int bufMaxSize,
1195  OUT_LENGTH_SHORT_Z int *bufSize,
1196  const BIGNUM *value1,
1197  const BIGNUM *value2,
1198  IN_ENUM( CRYPT_FORMAT ) \
1199  const CRYPT_FORMAT_TYPE formatType )
1200  {
1201  STREAM stream;
1202  int length = DUMMY_INIT, status;
1203 
1204  assert( isWritePtr( buffer, bufMaxSize ) );
1205  assert( isWritePtr( bufSize, sizeof( int ) ) );
1206  assert( isReadPtr( value1, sizeof( BIGNUM ) ) );
1207  assert( isReadPtr( value2, sizeof( BIGNUM ) ) );
1208 
1209  REQUIRES( bufMaxSize >= 40 && bufMaxSize < MAX_INTLENGTH_SHORT );
1210  REQUIRES( formatType > CRYPT_FORMAT_NONE && \
1211  formatType < CRYPT_FORMAT_LAST );
1212 
1213  /* Clear return values */
1214  memset( buffer, 0, min( 16, bufMaxSize ) );
1215  *bufSize = 0;
1216 
1217  /* In most cases the DLP and ECDLP formats are identical and we can just
1218  pass the call on to the DLP form, however SSH uses totally different
1219  signature formats depending on whether the signature is DSA or ECDSA,
1220  so we handle the SSH format explicitly here */
1221  if( formatType != CRYPT_IFORMAT_SSH )
1222  {
1223  return( encodeDLValuesFunction( buffer, bufMaxSize, bufSize,
1224  value1, value2, formatType ) );
1225  }
1226  sMemOpen( &stream, buffer, bufMaxSize );
1227  writeBignumInteger32( &stream, value1 );
1228  status = writeBignumInteger32( &stream, value2 );
1229  if( cryptStatusOK( status ) )
1230  length = stell( &stream );
1231  sMemDisconnect( &stream );
1232  if( cryptStatusError( status ) )
1233  return( status );
1234  *bufSize = length;
1235 
1236  return( CRYPT_OK );
1237  }
1238 
1239 /****************************************************************************
1240 * *
1241 * Context Access Routines *
1242 * *
1243 ****************************************************************************/
1244 
1245 STDC_NONNULL_ARG( ( 1 ) ) \
1246 void initKeyWrite( INOUT CONTEXT_INFO *contextInfoPtr )
1247  {
1248  const CRYPT_ALGO_TYPE cryptAlgo = contextInfoPtr->capabilityInfo->cryptAlgo;
1249  PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
1250 
1251  assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) && \
1252  contextInfoPtr->type == CONTEXT_PKC );
1253 
1254  /* Set the access method pointers */
1255  if( isDlpAlgo( cryptAlgo ) )
1256  {
1257  pkcInfo->writePublicKeyFunction = writePublicKeyDlpFunction;
1258  pkcInfo->writePrivateKeyFunction = writePrivateKeyDlpFunction;
1259  pkcInfo->encodeDLValuesFunction = encodeDLValuesFunction;
1260 
1261  return;
1262  }
1263 #if defined( USE_ECDH ) || defined( USE_ECDSA )
1264  if( isEccAlgo( cryptAlgo ) )
1265  {
1266  pkcInfo->writePublicKeyFunction = writePublicKeyEccFunction;
1267  pkcInfo->writePrivateKeyFunction = writePrivateKeyEccFunction;
1268  pkcInfo->encodeDLValuesFunction = encodeECDLValuesFunction;
1269 
1270  return;
1271  }
1272 #endif /* USE_ECDH || USE_ECDSA */
1273  pkcInfo->writePublicKeyFunction = writePublicKeyRsaFunction;
1274  pkcInfo->writePrivateKeyFunction = writePrivateKeyRsaFunction;
1275  }
1276 #else
1277 
1278 STDC_NONNULL_ARG( ( 1 ) ) \
1279 void initKeyWrite( INOUT CONTEXT_INFO *contextInfoPtr )
1280  {
1281  }
1282 #endif /* USE_PKC */