cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
dn.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate DN Routines *
4 * Copyright Peter Gutmann 1996-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "cert.h"
10  #include "dn.h"
11  #include "asn1.h"
12 #else
13  #include "cert/cert.h"
14  #include "cert/dn.h"
15  #include "enc_dec/asn1.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_CERTIFICATES
19 
20 /****************************************************************************
21 * *
22 * DN Information Tables *
23 * *
24 ****************************************************************************/
25 
26 /* A macro to make make declaring DN OIDs simpler */
27 
28 #define MKDNOID( value ) MKOID( "\x06\x03" value )
29 
30 /* Type information for DN components. If the OID doesn't correspond to a
31  valid cryptlib component (i.e. it's one of the 1,001 other odd things that
32  can be crammed into a DN) we can't directly identify it with a type but
33  instead return a simple integer value in the information table. This
34  works because the certificate component values don't start until x000 */
35 
36 static const DN_COMPONENT_INFO FAR_BSS certInfoOIDs[] = {
37  /* Useful components */
38  { CRYPT_CERTINFO_COMMONNAME, MKDNOID( "\x55\x04\x03" ),
39  "cn", 2, "oid.2.5.4.3", 11, CRYPT_MAX_TEXTSIZE, FALSE, TRUE },
40  { CRYPT_CERTINFO_COUNTRYNAME, MKDNOID( "\x55\x04\x06" ),
41  "c", 1, "oid.2.5.4.6", 11, 2, FALSE, FALSE },
42  { CRYPT_CERTINFO_LOCALITYNAME, MKDNOID( "\x55\x04\x07" ),
43  "l", 1, "oid.2.5.4.7", 11, 128, FALSE, TRUE },
44  { CRYPT_CERTINFO_STATEORPROVINCENAME, MKDNOID( "\x55\x04\x08" ),
45  "sp", 2, "oid.2.5.4.8", 11, 128, FALSE, TRUE },
46  { CRYPT_CERTINFO_ORGANIZATIONNAME, MKDNOID( "\x55\x04\x0A" ),
47  "o", 1, "oid.2.5.4.10", 12, CRYPT_MAX_TEXTSIZE, FALSE, TRUE },
48  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, MKDNOID( "\x55\x04\x0B" ),
49  "ou", 2, "oid.2.5.4.11", 12, CRYPT_MAX_TEXTSIZE, FALSE, TRUE },
50 
51  /* Non-useful components */
52  { 1, MKDNOID( "\x55\x04\x01" ), /* aliasObjectName (2 5 4 1) */
53  "oid.2.5.4.1", 11, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
54  { 2, MKDNOID( "\x55\x04\x02" ), /* knowledgeInformation (2 5 4 2) */
55  "oid.2.5.4.2", 11, NULL, 0, MAX_ATTRIBUTE_SIZE /*32768*/, FALSE, FALSE },
56  { 3, MKDNOID( "\x55\x04\x04" ), /* surname (2 5 4 4) */
57  "s", 1, "oid.2.5.4.4", 11, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
58  { 4, MKDNOID( "\x55\x04\x05" ), /* serialNumber (2 5 4 5) */
59  "sn", 2, "oid.2.5.4.5", 11, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
60  { 5, MKDNOID( "\x55\x04\x09" ), /* streetAddress (2 5 4 9) */
61  "st", 2, "oid.2.5.4.9", 11, 128, FALSE, FALSE },
62  { 6, MKDNOID( "\x55\x04\x0C" ), /* title (2 5 4 12) */
63  "t", 1, "oid.2.5.4.12", 12, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
64  { 7, MKDNOID( "\x55\x04\x0D" ), /* description (2 5 4 13) */
65  "d", 1, "oid.2.5.4.13", 12, 1024, FALSE, FALSE },
66  { 8, MKDNOID( "\x55\x04\x0E" ), /* searchGuide (2 5 4 14) */
67  "oid.2.5.4.14", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
68  { 9, MKDNOID( "\x55\x04\x0F" ), /* businessCategory (2 5 4 15) */
69  "bc", 2, "oid.2.5.4.15", 12, 128, FALSE, FALSE },
70  { 10, MKDNOID( "\x55\x04\x10" ), /* postalAddress (2 5 4 16) */
71  "oid.2.5.4.16", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
72  { 11, MKDNOID( "\x55\x04\x11" ), /* postalCode (2 5 4 17) */
73  "oid.2.5.4.17", 12, NULL, 0, 40, FALSE, FALSE },
74  { 12, MKDNOID( "\x55\x04\x12" ), /* postOfficeBox (2 5 4 18) */
75  "oid.2.5.4.18", 12, NULL, 0, 40, FALSE, FALSE },
76  { 13, MKDNOID( "\x55\x04\x13" ), /* physicalDeliveryOfficeName (2 5 4 19) */
77  "oid.2.5.4.19", 12, NULL, 0, 128, FALSE, FALSE },
78  { 14, MKDNOID( "\x55\x04\x14" ), /* telephoneNumber (2 5 4 20) */
79  "oid.2.5.4.20", 12, NULL, 0, 32, FALSE, FALSE },
80  { 15, MKDNOID( "\x55\x04\x15" ), /* telexNumber (2 5 4 21) */
81  "oid.2.5.4.21", 12, NULL, 0, 14, FALSE, FALSE },
82  { 16, MKDNOID( "\x55\x04\x16" ), /* teletexTerminalIdentifier (2 5 4 22) */
83  "oid.2.5.4.22", 12, NULL, 0, 24, FALSE, FALSE },
84  { 17, MKDNOID( "\x55\x04\x17" ), /* facsimileTelephoneNumber (2 5 4 23) */
85  "oid.2.5.4.23", 12, NULL, 0, 32, FALSE, FALSE },
86  { 18, MKDNOID( "\x55\x04\x18" ), /* x121Address (2 5 4 24) */
87  "oid.2.5.4.24", 12, NULL, 0, 15, FALSE, FALSE },
88  { 19, MKDNOID( "\x55\x04\x19" ), /* internationalISDNNumber (2 5 4 25) */
89  "isdn", 4, "oid.2.5.4.25", 12, 16, FALSE, FALSE },
90  { 20, MKDNOID( "\x55\x04\x1A" ), /* registeredAddress (2 5 4 26) */
91  "oid.2.5.4.26", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
92  { 21, MKDNOID( "\x55\x04\x1B" ), /* destinationIndicator (2 5 4 27) */
93  "oid.2.5.4.27", 12, NULL, 0, 128, FALSE, FALSE },
94  { 22, MKDNOID( "\x55\x04\x1C" ), /* preferredDeliveryMethod (2 5 4 28) */
95  "oid.2.5.4.28", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
96  { 23, MKDNOID( "\x55\x04\x1D" ), /* presentationAddress (2 5 4 29) */
97  "oid.2.5.4.29", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
98  { 24, MKDNOID( "\x55\x04\x1E" ), /* supportedApplicationContext (2 5 4 30) */
99  "oid.2.5.4.30", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
100  { 25, MKDNOID( "\x55\x04\x1F" ), /* member (2 5 4 31) */
101  "oid.2.5.4.31", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
102  { 26, MKDNOID( "\x55\x04\x20" ), /* owner (2 5 4 32) */
103  "oid.2.5.4.32", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
104  { 27, MKDNOID( "\x55\x04\x21" ), /* roleOccupant (2 5 4 33) */
105  "oid.2.5.4.33", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
106  { 28, MKDNOID( "\x55\x04\x22" ), /* seeAlso (2 5 4 34) */
107  "oid.2.5.4.34", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
108  /* 0x23-0x28 are certificates/CRLs and some weird encrypted directory components */
109  { 29, MKDNOID( "\x55\x04\x29" ), /* name (2 5 4 41) */
110  "oid.2.5.4.41", 12, NULL, 0, MAX_ATTRIBUTE_SIZE /*32768*/, FALSE, FALSE },
111  { 30, MKDNOID( "\x55\x04\x2A" ), /* givenName (2 5 4 42) */
112  "g", 1, "oid.2.5.4.42", 12, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
113  { 31, MKDNOID( "\x55\x04\x2B" ), /* initials (2 5 4 43) */
114  "i", 1, "oid.2.5.4.43", 12, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
115  { 32, MKDNOID( "\x55\x04\x2C" ), /* generationQualifier (2 5 4 44) */
116  "oid.2.5.4.44", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
117  { 33, MKDNOID( "\x55\x04\x2D" ), /* uniqueIdentifier (2 5 4 45) */
118  "oid.2.5.4.45", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
119  { 34, MKDNOID( "\x55\x04\x2E" ), /* dnQualifier (2 5 4 46) */
120  "oid.2.5.4.46", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
121  /* 0x2F-0x30 are directory components */
122  { 35, MKDNOID( "\x55\x04\x31" ), /* distinguishedName (2 5 4 49) */
123  "oid.2.5.4.49", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
124  { 36, MKDNOID( "\x55\x04\x32" ), /* uniqueMember (2 5 4 50) */
125  "oid.2.5.4.50", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
126  { 37, MKDNOID( "\x55\x04\x33" ), /* houseIdentifier (2 5 4 51) */
127  "oid.2.5.4.51", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
128  /* 0x34-0x3A are more certificates and weird encrypted directory components */
129  { 38, MKDNOID( "\x55\x04\x41" ), /* pseudonym (2 5 4 65) */
130  "oid.2.5.4.65", 12, NULL, 0, 128, FALSE, FALSE },
131  { 39, MKDNOID( "\x55\x04\x42" ), /* communicationsService (2 5 4 66) */
132  "oid.2.5.4.66", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
133  { 40, MKDNOID( "\x55\x04\x43" ), /* communicationsNetwork (2 5 4 67) */
134  "oid.2.5.4.67", 12, NULL, 0, CRYPT_MAX_TEXTSIZE, FALSE, FALSE },
135  /* 0x44-0x49 are more PKI-related attributes */
136  { 41, MKOID( "\x06\x0A\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x01" ), /* userid (0 9 2342 19200300 100 1 1) */
137  "uid", 3, NULL, 0, CRYPT_MAX_TEXTSIZE, TRUE, FALSE },
138  { 42, MKOID( "\x06\x0A\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x03" ), /* rfc822Mailbox (0 9 2342 19200300 100 1 3) */
139  "oid.0.9.2342.19200300.100.1.3", 29, NULL, 0, CRYPT_MAX_TEXTSIZE, TRUE, FALSE },
140  { 43, MKOID( "\x06\x0A\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19" ), /* domainComponent (0 9 2342 19200300 100 1 25) */
141  "dc", 2, "oid.0.9.2342.19200300.100.1.25", 30, CRYPT_MAX_TEXTSIZE, TRUE, FALSE },
142  { 44, MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01" ), /* emailAddress (1 2 840 113549 1 9 1) */
143  "email", 5, "oid.1.2.840.113549.1.9.1", 24, CRYPT_MAX_TEXTSIZE, TRUE, FALSE },
144  { 45, MKOID( "\x06\x07\x02\x82\x06\x01\x0A\x07\x14" ), /* nameDistinguisher (0 2 262 1 10 7 20) */
145  "oid.0.2.262.1.10.7.20", 21, NULL, 0, CRYPT_MAX_TEXTSIZE, TRUE, FALSE },
146 
147  { CRYPT_ATTRIBUTE_NONE, NULL }, { CRYPT_ATTRIBUTE_NONE, NULL }
148  };
149 
150 /* Check that a country code is valid */
151 
152 #define xA ( 1 << 0 )
153 #define xB ( 1 << 1 )
154 #define xC ( 1 << 2 )
155 #define xD ( 1 << 3 )
156 #define xE ( 1 << 4 )
157 #define xF ( 1 << 5 )
158 #define xG ( 1 << 6 )
159 #define xH ( 1 << 7 )
160 #define xI ( 1 << 8 )
161 #define xJ ( 1 << 9 )
162 #define xK ( 1 << 10 )
163 #define xL ( 1 << 11 )
164 #define xM ( 1 << 12 )
165 #define xN ( 1 << 13 )
166 #define xO ( 1 << 14 )
167 #define xP ( 1 << 15 )
168 #define xQ ( 1 << 16 )
169 #define xR ( 1 << 17 )
170 #define xS ( 1 << 18 )
171 #define xT ( 1 << 19 )
172 #define xU ( 1 << 20 )
173 #define xV ( 1 << 21 )
174 #define xW ( 1 << 22 )
175 #define xX ( 1 << 23 )
176 #define xY ( 1 << 24 )
177 #define xZ ( 1 << 25 )
178 
180 static BOOLEAN checkCountryCode( IN_BUFFER_C( 2 ) const BYTE *countryCode )
181  {
182  static const long countryCodes[] = { /* ISO 3166 code table */
183  /* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z */
184  /*A*/ xD|xE|xF|xG| xI| xL|xM|xN|xO| xQ|xR|xS|xT|xU| xW| xZ,
185  /*B*/ xA|xB| xD|xE|xF|xG|xH|xI|xJ| xM|xN|xO| xR|xS|xT| xV|xW| xY|xZ,
186  /*C*/ xA| xC|xD| xF|xG|xH|xI| xK|xL|xM|xN|xO| xR| xU|xV| xX|xY|xZ,
187  /*D*/ xE| xJ|xK| xM| xO| xZ,
188  /*E*/ xC| xE| xG|xH| xR|xS|xT,
189  /*F*/ xI|xJ|xK| xM| xO| xR,
190  /*G*/ xA|xB| xD|xE|xF| xH|xI| xL|xM|xN| xP|xQ|xR|xS|xT|xU| xW| xY,
191  /*H*/ xK| xM|xN| xR| xT|xU,
192  /*I*/ xD|xE| xL| xN|xO| xQ|xR|xS|xT,
193  /*J*/ xM| xO|xP,
194  /*K*/ xE| xG|xH|xI| xM|xN| xP| xR| xW| xY|xZ,
195  /*L*/ xA|xB|xC| xI| xK| xR|xS|xT|xU|xV| xY,
196  /*M*/ xA| xC|xD| xG|xH| xK|xL|xM|xN|xO|xP|xQ|xR|xS|xT|xU|xV|xW|xX|xY|xZ,
197  /*N*/ xA| xC| xE|xF|xG| xI| xL| xO|xP| xR| xU| xZ,
198  /*O*/ xM,
199  /*P*/ xA| xE|xF|xG|xH| xK|xL|xM|xN| xR|xS|xT| xW| xY,
200  /*Q*/ xA,
201  /*R*/ xE| xO| xU| xW,
202  /*S*/ xA|xB|xC|xD|xE| xG|xH|xI|xJ|xK|xL|xM|xN|xO| xR| xT| xV| xY|xZ,
203  /*T*/ xC|xD| xF|xG|xH| xJ|xK|xL|xM|xN|xO| xR| xT| xV|xW| xZ,
204  /*U*/ xA| xG| xM| xS| xY|xZ,
205  /*V*/ xA| xC| xE| xG| xI| xN| xU,
206  /*W*/ xF| xS,
207  /*X*/ 0,
208  /*Y*/ xE| xT|xU,
209  /*Z*/ xA| xM| xW,
210  0, 0 /* Catch overflows */
211  };
212  const int cc0 = countryCode[ 0 ] - 'A';
213  const int cc1 = countryCode[ 1 ] - 'A';
214 
215  assert( isReadPtr( countryCode, 2 ) );
216 
217  /* Check that the country code is present in the table of valid ISO 3166
218  codes. Note the explicit declaration of the one-bit as '1L', this is
219  required because the shift amount can be greater than the word size on
220  16-bit systems */
221  if( cc0 < 0 || cc0 > 25 || cc1 < 0 || cc1 > 25 )
222  return( FALSE );
223  return( ( countryCodes[ cc0 ] & ( 1L << cc1 ) ) ? TRUE : FALSE );
224  }
225 
226 /* Determine the sort priority for DN components */
227 
229 static int dnSortOrder( IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type )
230  {
231  static const MAP_TABLE dnSortOrderTbl[] = {
238  { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
239  };
240  int status, value;
241 
242  REQUIRES( type >= CRYPT_CERTINFO_FIRST_DN && \
243  type <= CRYPT_CERTINFO_LAST_DN );
244 
245  status = mapValue( type, &value, dnSortOrderTbl,
246  FAILSAFE_ARRAYSIZE( dnSortOrderTbl, MAP_TABLE ) );
247  ENSURES( cryptStatusOK( status ) );
248 
249  return( value );
250  }
251 
252 /****************************************************************************
253 * *
254 * Utility Functions *
255 * *
256 ****************************************************************************/
257 
258 /* Check whether a DN component is valid. This is used because outside this
259  module DN components are referenced via opaque pointers, and the
260  following provides a sanity-check in case the wrong ponter value is
261  passed in */
262 
264 static BOOLEAN isDNComponentValid( const DN_COMPONENT *dnComponent )
265  {
266  assert( isReadPtr( dnComponent, sizeof( DN_COMPONENT ) ) );
267 
268  /* Check that various fields with fixed-range values are within bounds.
269  This isn't an infallible check, but the chances of an arbitrary
270  pointer being that's passed to us passing this check is pretty
271  miniscule */
272  if( dnComponent->type < 1 || \
273  ( dnComponent->type > 50 && \
274  dnComponent->type < CRYPT_CERTINFO_FIRST_DN ) ||
275  dnComponent->type > CRYPT_CERTINFO_LAST_DN )
276  return( FALSE );
277  if( dnComponent->typeInfo == NULL )
278  return( FALSE );
279  if( dnComponent->flags < DN_FLAG_NONE ||
280  dnComponent->flags > DN_FLAG_MAX )
281  return( FALSE );
282  if( dnComponent->valueLength < 0 || \
283  dnComponent->valueLength > MAX_INTLENGTH_SHORT )
284  return( FALSE );
285  if( dnComponent->asn1EncodedStringType < 0 || \
286  dnComponent->asn1EncodedStringType > 0xFF || \
287  dnComponent->encodedRDNdataSize < 0 || \
288  dnComponent->encodedRDNdataSize > MAX_INTLENGTH_SHORT || \
289  dnComponent->encodedAVAdataSize < 0 || \
290  dnComponent->encodedAVAdataSize > MAX_INTLENGTH_SHORT )
291  return( FALSE );
292 
293  return( TRUE );
294  }
295 
296 /* Find a DN component in a DN component list by type and by OID. This also
297  takes a count parameter to return the n'th occurrence of a DN component.
298  Note that we use counted-access rather than the usual getFirst()/getNext()
299  enumeration mechanism because some of the accesses are coming from outside
300  cryptlib and may be non-atomic. In other words there's no guarantee that
301  the caller won't perform a delete between getNext()'s, leaving a dangling
302  reference to trip up the next getNext() call */
303 
305 static DN_COMPONENT *findDNComponent( const DN_COMPONENT *dnComponentList,
307  IN_RANGE( 0, 100 ) const int count,
308  IN_BUFFER_OPT( valueLength ) const void *value,
309  IN_LENGTH_SHORT_Z const int valueLength )
310  {
311  const DN_COMPONENT *listPtr;
312  int matchCount = 0, iterationCount;
313 
314  assert( isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
315  assert( ( value == NULL && valueLength == 0 ) || \
316  isReadPtr( value, valueLength ) );
317  /* We may be doing the lookup purely by type */
318 
319  REQUIRES_N( type >= CRYPT_CERTINFO_FIRST_DN && \
320  type <= CRYPT_CERTINFO_LAST_DN );
321  REQUIRES_N( count >= 0 && count <= 100 );
322  REQUIRES_N( ( value == NULL && valueLength == 0 ) || \
323  ( value != NULL && \
324  valueLength > 0 && valueLength < MAX_INTLENGTH_SHORT ) );
325  REQUIRES_N( ( value == NULL && count >= 0 ) || \
326  ( value != NULL && count == 0 ) );
327 
328  /* Find the position of this component in the list */
329  for( listPtr = dnComponentList, iterationCount = 0;
330  listPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
331  listPtr = listPtr->next, iterationCount++ )
332  {
333  /* If it's of a different type then it can't be a match */
334  if( listPtr->type != type )
335  continue;
336 
337  /* If we're doing the lookup purely by type then we've found a
338  match */
339  if( value == NULL )
340  {
341  /* If we're looking for the n-th match rather than the first
342  matching item, continue if we haven't reached the n-th item
343  yet */
344  if( matchCount++ < count )
345  continue;
346  return( ( DN_COMPONENT * ) listPtr );
347  }
348 
349  /* Check for a match by value */
350  if( listPtr->valueLength == valueLength && \
351  !memcmp( listPtr->value, value, valueLength ) )
352  return( ( DN_COMPONENT * ) listPtr );
353  }
354  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MED );
355 
356  return( NULL );
357  }
358 
360 static DN_COMPONENT *findDNComponentByOID( const DN_COMPONENT *dnComponentList,
361  IN_BUFFER( oidLength ) const BYTE *oid,
362  IN_LENGTH_OID const int oidLength )
363  {
364  const DN_COMPONENT *listPtr;
365  int iterationCount;
366 
367  assert( isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
368  assert( isReadPtr( oid, oidLength ) );
369 
370  REQUIRES_N( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE && \
371  oidLength == sizeofOID( oid ) );
372 
373  /* Find the position of this component in the list */
374  for( listPtr = dnComponentList, iterationCount = 0;
375  listPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
376  listPtr = listPtr->next, iterationCount++ )
377  {
378  const DN_COMPONENT_INFO *dnComponentInfo = listPtr->typeInfo;
379 
380  if( oidLength == sizeofOID( dnComponentInfo->oid ) && \
381  !memcmp( dnComponentInfo->oid, oid, oidLength ) )
382  return( ( DN_COMPONENT * ) listPtr );
383  }
384  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MED );
385 
386  return( NULL );
387  }
388 
389 /* Find DN information by type, by OID, and by string label */
390 
391 CHECK_RETVAL_PTR \
392 static const DN_COMPONENT_INFO *findDNInfo( IN_INT const int type )
393  {
394  int i;
395 
396  REQUIRES_N( ( type >= CRYPT_CERTINFO_FIRST_DN && \
397  type <= CRYPT_CERTINFO_LAST_DN ) || \
398  ( type > 0 && type < 50 ) );
399 
400  /* Find the type information for this component */
401  for( i = 0; certInfoOIDs[ i ].oid != NULL && \
402  i < FAILSAFE_ARRAYSIZE( certInfoOIDs, DN_COMPONENT_INFO );
403  i++ )
404  {
405  if( certInfoOIDs[ i ].type == type )
406  return( &certInfoOIDs[ i ] );
407  }
408 
410  }
411 
413 const DN_COMPONENT_INFO *findDNInfoByOID( IN_BUFFER( oidLength ) const BYTE *oid,
414  IN_LENGTH_OID const int oidLength )
415  {
416  int i;
417 
418  assert( isReadPtr( oid, oidLength ) );
419 
420  REQUIRES_N( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE && \
421  oidLength == sizeofOID( oid ) );
422 
423  for( i = 0; certInfoOIDs[ i ].oid != NULL && \
424  i < FAILSAFE_ARRAYSIZE( certInfoOIDs, DN_COMPONENT_INFO );
425  i++ )
426  {
427  const DN_COMPONENT_INFO *certInfoOID = &certInfoOIDs[ i ];
428 
429  /* Perform a quick check of the OID. The majority of all DN OIDs
430  are of the form (2 5 4 n), encoded as 0x06 0x03 0x55 0x04 0xnn,
431  so we compare the byte at offset 4 for the quick-reject match
432  before we go for the full OID match */
433  if( certInfoOID->oid[ 4 ] == oid[ 4 ] && \
434  !memcmp( certInfoOID->oid, oid, oidLength ) )
435  return( certInfoOID );
436  }
437  ENSURES_N( i < FAILSAFE_ARRAYSIZE( certInfoOIDs, DN_COMPONENT_INFO ) );
438 
439  return( NULL );
440  }
441 
442 #ifdef USE_CERT_DNSTRING
443 
445 const DN_COMPONENT_INFO *findDNInfoByLabel( IN_BUFFER( labelLength ) const char *label,
446  IN_LENGTH_SHORT const int labelLength )
447  {
448  int i;
449 
450  assert( isReadPtr( label, labelLength ) );
451 
452  REQUIRES_N( labelLength > 0 && labelLength < MAX_INTLENGTH_SHORT );
453 
454  for( i = 0; certInfoOIDs[ i ].oid != NULL && \
455  i < FAILSAFE_ARRAYSIZE( certInfoOIDs, DN_COMPONENT_INFO );
456  i++ )
457  {
458  const DN_COMPONENT_INFO *certInfoOID = &certInfoOIDs[ i ];
459 
460  if( certInfoOID->nameLen == labelLength && \
461  !strCompare( certInfoOID->name, label, labelLength ) )
462  return( certInfoOID );
463  if( certInfoOID->altName != NULL && \
464  certInfoOID->altNameLen == labelLength && \
465  !strCompare( certInfoOID->altName, label, labelLength ) )
466  return( certInfoOID );
467  }
468  ENSURES_N( i < FAILSAFE_ARRAYSIZE( certInfoOIDs, DN_COMPONENT_INFO ) );
469 
470  return( NULL );
471  }
472 #endif /* USE_CERT_DNSTRING */
473 
474 /* Find the appropriate location in a DN to insert a new component */
475 
476 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 4, 5 ) ) \
477 static int findDNInsertPoint( const DN_COMPONENT *listHeadPtr,
478  IN_INT const int type,
479  const BOOLEAN fromExternalSource,
480  OUT_OPT_PTR DN_COMPONENT **insertPointPtrPtr,
482  CRYPT_ERRTYPE_TYPE *errorType )
483  {
484  const DN_COMPONENT *insertPoint, *prevElement = NULL;
485  int newValueSortOrder, iterationCount;
486 
487  assert( listHeadPtr == NULL || \
488  isReadPtr( listHeadPtr, sizeof( DN_COMPONENT ) ) );
489  assert( isWritePtr( insertPointPtrPtr, sizeof( DN_COMPONENT * ) ) );
490  assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
491 
492  REQUIRES( ( type >= CRYPT_CERTINFO_FIRST_DN && \
493  type <= CRYPT_CERTINFO_LAST_DN ) || \
494  ( type > 0 && type < 50 ) );
495 
496  /* Clear return value */
497  *insertPointPtrPtr = NULL;
498 
499  /* If it's being read from encoded certificate data just append it to
500  the end of the list */
501  if( fromExternalSource )
502  {
503  for( insertPoint = listHeadPtr, iterationCount = 0;
504  insertPoint->next != NULL && \
505  iterationCount < FAILSAFE_ITERATIONS_MED;
506  insertPoint = insertPoint->next, iterationCount++ );
507  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
508  *insertPointPtrPtr = ( DN_COMPONENT * ) insertPoint;
509 
510  return( CRYPT_OK );
511  }
512 
513  /* Get the sort order for the new value and make sure that it's valid */
514  newValueSortOrder = dnSortOrder( type );
515  if( cryptStatusError( newValueSortOrder ) )
516  return( newValueSortOrder );
517 
518  /* Find the location to insert it */
519  for( insertPoint = listHeadPtr, iterationCount = 0;
520  insertPoint != NULL && \
521  newValueSortOrder >= dnSortOrder( insertPoint->type ) && \
522  iterationCount < FAILSAFE_ITERATIONS_MED;
523  insertPoint = insertPoint->next, iterationCount++ )
524  {
525  /* Make sure that this component isn't already present. We only
526  allow a single DN component of any type to keep things simple for
527  the user and to avoid potential problems with implementations
528  that don't handle more than one instance of a given DN component
529  too well */
530  if( insertPoint->type == type )
531  {
532  if( errorType != NULL )
533  *errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
534  return( CRYPT_ERROR_INITED );
535  }
536 
537  prevElement = insertPoint;
538  }
539  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
540  *insertPointPtrPtr = ( DN_COMPONENT * ) prevElement;
541 
542  return( CRYPT_OK );
543  }
544 
545 /****************************************************************************
546 * *
547 * Add DN Components *
548 * *
549 ****************************************************************************/
550 
551 /* Insert a DN component into a list. The type can be either a
552  CRYPT_CERTINFO_xxx value, indicating that it's a standard DN component,
553  or a small integer denoting a recognised but nonstandard DN component.
554  In the latter case we don't try to sort the component into the correct
555  position */
556 
557 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 3, 7 ) ) \
558 int insertDNstring( INOUT DN_COMPONENT **dnComponentListPtrPtr,
559  IN_INT const int type,
560  IN_BUFFER( valueLength ) const void *value,
561  IN_LENGTH_SHORT const int valueLength,
562  IN_RANGE( 1, 20 ) const int valueStringType,
563  IN_FLAGS_Z( DN ) const int flags,
565  CRYPT_ERRTYPE_TYPE *errorType )
566  {
567  const DN_COMPONENT_INFO *dnComponentInfo = NULL;
568  DN_COMPONENT *listHeadPtr = *dnComponentListPtrPtr;
569  DN_COMPONENT *newElement, *insertPoint;
570  BYTE countryCode[ 2 + 8 ];
571 
572  assert( isWritePtr( dnComponentListPtrPtr, sizeof( DN_COMPONENT * ) ) );
573  assert( listHeadPtr == NULL || \
574  isWritePtr( listHeadPtr, sizeof( DN_COMPONENT ) ) );
575  assert( isReadPtr( value, valueLength ) );
576  assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
577 
578  REQUIRES( listHeadPtr == NULL || isDNComponentValid( listHeadPtr ) );
579  REQUIRES( ( type >= CRYPT_CERTINFO_FIRST_DN && \
580  type <= CRYPT_CERTINFO_LAST_DN ) || \
581  ( type > 0 && type < 50 ) );
582  REQUIRES( valueLength > 0 && valueLength < MAX_INTLENGTH_SHORT );
583  REQUIRES( valueStringType >= 1 && valueStringType <= 20 );
584  REQUIRES( flags >= DN_FLAG_NONE && flags <= DN_FLAG_MAX );
585 
586  /* If the DN is locked against modification we can't make any further
587  updates */
588  if( listHeadPtr != NULL && ( listHeadPtr->flags & DN_FLAG_LOCKED ) )
589  return( CRYPT_ERROR_INITED );
590 
591  /* Find the type information for this component */
592  dnComponentInfo = findDNInfo( type );
593  ENSURES( dnComponentInfo != NULL );
594 
595  /* Make sure that the length is valid. If it's being read from an
596  encoded form we allow abnormally-long lengths (although we still keep
597  them within a sensible limit) since this is better than failing to
598  read a certificate because it contains a broken DN. In addition if a
599  widechar string is OK we allow a range up to the maximum byte count
600  defined by the widechar size */
601 #ifdef USE_WIDECHARS
602  if( valueLength > ( ( flags & DN_FLAG_NOCHECK ) ? \
604  ( dnComponentInfo->wcsOK ) ? \
605  ( WCSIZE * dnComponentInfo->maxLength ) : \
606  dnComponentInfo->maxLength ) )
607 #else
608  if( valueLength > ( ( flags & DN_FLAG_NOCHECK ) ? \
609  MAX_ATTRIBUTE_SIZE : dnComponentInfo->maxLength ) )
610 #endif /* USE_WIDECHARS */
611  {
612  if( errorType != NULL )
613  *errorType = CRYPT_ERRTYPE_ATTR_SIZE;
614  return( CRYPT_ARGERROR_NUM1 );
615  }
616 
617  /* Find the correct place in the list to insert the new element */
618  if( listHeadPtr != NULL )
619  {
620  int status;
621 
622  status = findDNInsertPoint( listHeadPtr, type,
623  ( flags & DN_FLAG_NOCHECK ) ? \
624  TRUE : FALSE,
625  &insertPoint, errorType );
626  if( cryptStatusError( status ) )
627  return( status );
628  }
629  else
630  {
631  /* It's an empty list, insert the new element at the start */
632  insertPoint = NULL;
633  }
634 
635  /* If it's a country code, force it to uppercase as per ISO 3166 */
636  if( type == CRYPT_CERTINFO_COUNTRYNAME )
637  {
638  const BYTE *dnStrPtr = value;
639 
640  /* The country code must be exactly two characeters long */
641  if( valueLength != 2 )
642  return( CRYPT_ERROR_BADDATA );
643 
644  /* Note: When this code is run under BoundsChecker 6.x the toUpper()
645  conversion will produce garbage on any call after the first one
646  resulting in the following checks failing */
647  countryCode[ 0 ] = intToByte( toUpper( dnStrPtr[ 0 ] ) );
648  countryCode[ 1 ] = byteToInt( toUpper( dnStrPtr[ 1 ] ) );
649  if( flags & DN_FLAG_NOCHECK )
650  {
651  /* 'UK' isn't an ISO 3166 country code but may be found in some
652  certificates. If we find this we quietly convert it to the
653  correct value */
654  if( !memcmp( countryCode, "UK", 2 ) )
655  memcpy( countryCode, "GB", 2 );
656  }
657  else
658  {
659  /* Make sure that the country code is valid */
660  if( !checkCountryCode( countryCode ) )
661  {
662  if( errorType != NULL )
663  *errorType = CRYPT_ERRTYPE_ATTR_VALUE;
664  return( CRYPT_ERROR_INVALID );
665  }
666  }
667 
668  /* We've fixed up the coutry code information if required, make sure
669  that we add the fixed form rather than the original */
670  value = countryCode;
671  }
672 
673  /* Allocate memory for the new element and copy over the information */
674  if( ( newElement = ( DN_COMPONENT * ) \
675  clAlloc( "insertDNstring", sizeof( DN_COMPONENT ) + \
676  valueLength ) ) == NULL )
677  return( CRYPT_ERROR_MEMORY );
678  initVarStruct( newElement, DN_COMPONENT, valueLength );
679  newElement->type = type;
680  newElement->typeInfo = dnComponentInfo;
681  memcpy( newElement->value, value, valueLength );
682  newElement->valueLength = valueLength;
683  newElement->valueStringType = valueStringType;
684  newElement->flags = flags;
685 
686  /* Link it into the list */
687  insertDoubleListElement( ( DN_COMPONENT ** ) dnComponentListPtrPtr,
688  insertPoint, newElement );
689 
690  return( CRYPT_OK );
691  }
692 
693 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
694 int insertDNComponent( INOUT_PTR DN_PTR **dnComponentListPtrPtr,
696  IN_BUFFER( valueLength ) const void *value,
697  IN_LENGTH_SHORT const int valueLength,
699  CRYPT_ERRTYPE_TYPE *errorType )
700  {
701  int valueStringType, dummy1, dummy2, status;
702 
703  assert( isWritePtr( dnComponentListPtrPtr,
704  sizeof( DN_COMPONENT_INFO * ) ) );
705  assert( isReadPtr( value, valueLength ) );
706  assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
707 
708  REQUIRES( componentType >= CRYPT_CERTINFO_FIRST_DN && \
709  componentType <= CRYPT_CERTINFO_LAST_DN );
710  REQUIRES( valueLength > 0 && valueLength < MAX_INTLENGTH_SHORT );
711 
712  /* The value is coming from an external source, make sure that it's
713  representable as a certificate string type. All that we care
714  about here is the validity so we ignore the returned encoding
715  information */
716  status = getAsn1StringInfo( value, valueLength, &valueStringType,
717  &dummy1, &dummy2 );
718  if( cryptStatusError( status ) )
719  {
720  *errorType = CRYPT_ERRTYPE_ATTR_VALUE;
721  return( CRYPT_ARGERROR_STR1 );
722  }
723 
724  return( insertDNstring( ( DN_COMPONENT ** ) dnComponentListPtrPtr,
725  componentType, value, valueLength,
726  valueStringType, 0, errorType ) );
727  }
728 
729 /****************************************************************************
730 * *
731 * Delete DN Components *
732 * *
733 ****************************************************************************/
734 
735 /* Delete a DN component from a list */
736 
737 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
738 static int deleteComponent( INOUT_PTR DN_COMPONENT **dnComponentListPtrPtr,
739  INOUT DN_COMPONENT *theElement )
740  {
741  assert( isWritePtr( dnComponentListPtrPtr, sizeof( DN_COMPONENT * ) ) );
742  assert( isWritePtr( theElement, sizeof( DN_COMPONENT ) ) );
743 
744  /* Remove the item from the list */
745  deleteDoubleListElement( dnComponentListPtrPtr, theElement );
746 
747  /* Clear all data in the list item and free the memory */
748  endVarStruct( theElement, DN_COMPONENT );
749  clFree( "deleteComponent", theElement );
750 
751  return( CRYPT_OK );
752  }
753 
755 int deleteDNComponent( INOUT_PTR DN_PTR **dnComponentListPtrPtr,
757  IN_BUFFER_OPT( valueLength ) const void *value,
758  IN_LENGTH_SHORT const int valueLength )
759  {
760  DN_COMPONENT *listHeadPtr = *dnComponentListPtrPtr;
761  DN_COMPONENT *itemToDelete;
762 
763  assert( isWritePtr( dnComponentListPtrPtr, sizeof( DN_COMPONENT * ) ) );
764  assert( listHeadPtr == NULL || \
765  isWritePtr( listHeadPtr, sizeof( DN_COMPONENT ) ) );
766  assert( ( value == NULL && valueLength == 0 ) ||
767  isReadPtr( value, valueLength ) );
768  /* We may be doing the delete purely by type */
769 
770  REQUIRES( listHeadPtr == NULL || isDNComponentValid( listHeadPtr ) );
772  REQUIRES( ( value == NULL && valueLength == 0 ) || \
773  ( value != NULL && \
774  valueLength >= 0 && valueLength < MAX_INTLENGTH_SHORT ) );
775 
776  /* Trying to delete from an empty DN always fails */
777  if( listHeadPtr == NULL )
778  return( CRYPT_ERROR_NOTFOUND );
779 
780  /* If the DN is locked against modification then we can't make any
781  further updates */
782  if( listHeadPtr->flags & DN_FLAG_LOCKED )
783  return( CRYPT_ERROR_PERMISSION );
784 
785  /* Find the component in the list and delete it */
786  itemToDelete = findDNComponent( listHeadPtr, type, 0,
787  value, valueLength );
788  if( itemToDelete == NULL )
789  return( CRYPT_ERROR_NOTFOUND );
790  return( deleteComponent( ( DN_COMPONENT ** ) dnComponentListPtrPtr,
791  itemToDelete ) );
792  }
793 
794 /* Delete a DN */
795 
796 STDC_NONNULL_ARG( ( 1 ) ) \
797 void deleteDN( DN_PTR **dnComponentListPtrPtr )
798  {
799  DN_COMPONENT *listPtr;
800  int iterationCount;
801 
802  assert( isWritePtr( dnComponentListPtrPtr, sizeof( DN_COMPONENT * ) ) );
803 
804  /* Destroy all DN items */
805  for( listPtr = *dnComponentListPtrPtr, iterationCount = 0;
806  listPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
807  iterationCount++ )
808  {
809  DN_COMPONENT *itemToFree = listPtr;
810 
811  /* Another gcc bug, this time in gcc 4.x for 64-bit architectures
812  (confirmed for x86-64 and ppc64) in which it removes an empty-
813  list check in deleteDoubleListElement() (in fact the emitted
814  code bears only a passing resemblance to the actual source code,
815  this appears to be a variant of the broken handling of the
816  nonnull attribute described in misc/analyse.h). The only possible
817  workaround seems to be to omit the call to deleteComponent() and
818  just delete the item directly */
819  listPtr = listPtr->next;
820 #if defined( __GNUC__ ) && ( __GNUC__ == 4 ) && 0
821  /* The addition of the REQUIRES() preconditions to
822  deleteDoubleListElement() seem to have fixed the gcc problem,
823  either that or it was only present in some early 4.0.x versions */
824  deleteDoubleListElement( dnComponentListPtrPtr, itemToFree );
825  endVarStruct( itemToFree, DN_COMPONENT );
826  clFree( "deleteComponent", itemToFree );
827 #else
828  ( void ) deleteComponent( &itemToFree, itemToFree );
829 #endif /* gcc 4.x on 64-bit architectures bug workaround */
830  }
831  ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MED );
832 
833  /* Mark the list as being empty */
834  *dnComponentListPtrPtr = NULL;
835  }
836 
837 /****************************************************************************
838 * *
839 * Miscellaneous DN Component Functions *
840 * *
841 ****************************************************************************/
842 
843 /* Get DN component information */
844 
845 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
846 int getDNComponentInfo( INOUT const DN_PTR *dnComponentList,
849  {
850  const DN_COMPONENT *dnComponent = dnComponentList;
851 
852  assert( isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
853  assert( isWritePtr( type, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
854  assert( isWritePtr( dnContinues, sizeof( BOOLEAN ) ) );
855 
856  REQUIRES( isDNComponentValid( dnComponent ) );
857 
858  /* Clear return values */
859  *type = CRYPT_ATTRIBUTE_NONE;
860  *dnContinues = FALSE;
861 
862  /* Return the component information to the caller. The dnContinues
863  value is a somewhat oddball piece of information that's used in
864  conjunction with compareDN() when checking subsets of DNs, for
865  example to see if a DN subset contains more than one element */
866  if( dnComponent->type >= CRYPT_CERTINFO_FIRST_DN && \
867  dnComponent->type <= CRYPT_CERTINFO_LAST_DN )
868  *type = dnComponent->type;
869  if( dnComponent->next != NULL )
870  *dnContinues = TRUE;
871 
872  return( CRYPT_OK );
873  }
874 
875 /* Get the value of a DN component. This also takes a count parameter to
876  return the n'th occurrence of a DN component, see the comment for
877  findDNComponent() for details */
878 
879 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
880 int getDNComponentValue( const DN_PTR *dnComponentList,
882  IN_RANGE( 0, 100 ) const int count,
884  *valueLength ) void *value,
886  OUT_LENGTH_SHORT_Z int *valueLength )
887  {
888  const DN_COMPONENT *dnComponent;
889 
890  assert( isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
891  assert( ( value == NULL && valueMaxLength == 0 ) || \
892  ( isWritePtr( value, valueMaxLength ) ) );
893  assert( isWritePtr( valueLength, sizeof( int ) ) );
894 
895  REQUIRES( isDNComponentValid( dnComponentList ) );
896  REQUIRES( type >= CRYPT_CERTINFO_FIRST_DN && \
897  type <= CRYPT_CERTINFO_LAST_DN );
898  REQUIRES( count >= 0 && count <= 100 );
899  REQUIRES( ( value == NULL && valueMaxLength == 0 ) || \
900  ( value != NULL && \
901  valueMaxLength >= 0 && \
902  valueMaxLength < MAX_INTLENGTH_SHORT ) );
903 
904  /* Clear return values */
905  *valueLength = 0;
906  if( value != NULL )
907  memset( value, 0, min( 16, valueMaxLength ) );
908 
909  dnComponent = findDNComponent( dnComponentList, type, count, NULL, 0 );
910  if( dnComponent == NULL )
911  return( CRYPT_ERROR_NOTFOUND );
912  return( attributeCopyParams( value, valueMaxLength, valueLength,
913  dnComponent->value,
914  dnComponent->valueLength ) );
915  }
916 
917 /* Compare two DNs. Since this is used for constraint comparisons as well
918  as just strict equality checks we provide a flag which, if set, returns
919  a match if the first DN is a proper substring of the second DN. We
920  optionally return a pointer to the first mis-matching element in the
921  first DN in case the caller wants to perform further actions with it */
922 
923 CHECK_RETVAL_BOOL \
924 BOOLEAN compareDN( IN_OPT const DN_PTR *dnComponentList1,
925  IN_OPT const DN_PTR *dnComponentList2,
926  const BOOLEAN dn1substring,
927  OUT_OPT_PTR DN_PTR **mismatchPointPtrPtr )
928  {
929  DN_COMPONENT *dn1ptr, *dn2ptr;
930  int iterationCount;
931 
932  assert( dnComponentList1 == NULL || \
933  isReadPtr( dnComponentList1, sizeof( DN_COMPONENT * ) ) );
934  assert( dnComponentList2 == NULL || \
935  isReadPtr( dnComponentList2, sizeof( DN_COMPONENT * ) ) );
936  assert( mismatchPointPtrPtr == NULL || \
937  isWritePtr( mismatchPointPtrPtr, sizeof( DN_PTR * ) ) );
938 
939  REQUIRES_B( !( dn1substring == FALSE && \
940  mismatchPointPtrPtr != NULL ) );
941  REQUIRES_B( dnComponentList1 == NULL || \
942  isDNComponentValid( dnComponentList1 ) );
943  REQUIRES_B( dnComponentList2 == NULL || \
944  isDNComponentValid( dnComponentList2 ) );
945 
946  /* Clear return value */
947  if( mismatchPointPtrPtr )
948  *mismatchPointPtrPtr = NULL;
949 
950  /* Check each DN component for equality */
951  for( dn1ptr = ( DN_COMPONENT * ) dnComponentList1, \
952  dn2ptr = ( DN_COMPONENT * ) dnComponentList2,
953  iterationCount = 0;
954  dn1ptr != NULL && dn2ptr != NULL && \
955  iterationCount < FAILSAFE_ITERATIONS_MED;
956  dn1ptr = dn1ptr->next, dn2ptr = dn2ptr->next, \
957  iterationCount++ )
958  {
959  /* If the RDN types differ, the DNs don't match */
960  if( dn1ptr->type != dn2ptr->type )
961  {
962  if( mismatchPointPtrPtr != NULL )
963  *mismatchPointPtrPtr = dn1ptr;
964  return( FALSE );
965  }
966 
967  /* Compare the current RDNs. In theory we should be using the
968  complex and arcane X.500 name comparison rules but no-one in
969  their right mind actually does this since they're almost
970  impossible to get right. Since everyone else uses memcpy()/
971  memcmp() to handle DN components it's safe to use it here (sic
972  faciunt omnes). This also avoids any security problems arising
973  from the complexity of the code necessary to implement the X.500
974  matching rules */
975  if( dn1ptr->valueLength != dn2ptr->valueLength || \
976  memcmp( dn1ptr->value, dn2ptr->value, dn1ptr->valueLength ) ||
977  ( dn1ptr->flags & DN_FLAGS_COMPARE_MASK ) != \
978  ( dn1ptr->flags & DN_FLAGS_COMPARE_MASK ) )
979  {
980  if( mismatchPointPtrPtr != NULL )
981  *mismatchPointPtrPtr = dn1ptr;
982  return( FALSE );
983  }
984  }
985  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
986 
987  /* If we've reached the end of both DNs or we're looking for a substring
988  match (which means that the match ended when it reached the end of
989  the first DN, making it a proper substring of the second) then the
990  two match */
991  if( dn1ptr == NULL && dn2ptr == NULL )
992  return( TRUE );
993  if( dn1substring && dn1ptr == NULL )
994  return( TRUE );
995 
996  /* We've reached the end of the DN without finding a match */
997  if( mismatchPointPtrPtr != NULL )
998  *mismatchPointPtrPtr = dn1ptr;
999  return( FALSE );
1000  }
1001 
1002 /* Copy a DN */
1003 
1004 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1005 int copyDN( OUT_OPT_PTR DN_PTR **dnDest, IN_OPT const DN_PTR *dnSrc )
1006  {
1007  const DN_COMPONENT *srcPtr;
1008  DN_COMPONENT **dnDestPtrPtr = ( DN_COMPONENT ** ) dnDest;
1009  DN_COMPONENT *destPtr = NULL;
1010  int iterationCount;
1011 
1012  assert( isWritePtr( dnDest, sizeof( DN_COMPONENT * ) ) );
1013  assert( dnSrc == NULL || isReadPtr( dnSrc, sizeof( DN_COMPONENT * ) ) );
1014 
1015  REQUIRES( dnSrc == NULL || isDNComponentValid( dnSrc ) );
1016 
1017  /* Clear return value */
1018  *dnDest = NULL;
1019 
1020  /* Copy each element in the source DN */
1021  for( srcPtr = dnSrc, iterationCount= 0;
1022  srcPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
1023  srcPtr = srcPtr->next, iterationCount++ )
1024  {
1025  DN_COMPONENT *newElement;
1026 
1027  /* Allocate memory for the new element and copy over the
1028  information. Since we're copying over the contents of an
1029  existing DN_COMPONENT structure we have to zero the list links
1030  after the copy */
1031  if( ( newElement = ( DN_COMPONENT * ) \
1032  clAlloc( "copyDN", \
1033  sizeofVarStruct( srcPtr, DN_COMPONENT ) ) ) == NULL )
1034  {
1035  deleteDN( dnDest );
1036  return( CRYPT_ERROR_MEMORY );
1037  }
1038  copyVarStruct( newElement, srcPtr, DN_COMPONENT );
1039  newElement->prev = newElement->next = NULL;
1040 
1041  /* Link it into the list */
1042  insertDoubleListElement( dnDestPtrPtr, destPtr, newElement );
1043  destPtr = newElement;
1044  }
1045  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
1046 
1047  return( CRYPT_OK );
1048  }
1049 
1050 /* Check the validity and well-formedness of a DN. The check for the bottom
1051  of the DN (common name) and top (country) are made configurable, DNs that
1052  act as filters (e.g. path constraints) may not have the lower DN parts
1053  present and certificate requests submitted to CAs that set the country
1054  themselves may not have the country present.
1055 
1056  We also check that there's only one country present (the use of DN
1057  strings allows more than one to be set). In addition if an explicit
1058  check for well-formedness is being done then we check for no more than
1059  one CN and no more than one AVA per RDN because the behvaiour of
1060  different implementations when they encounter these is more or less
1061  random */
1062 
1063 CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 4 ) ) \
1064 int checkDN( IN_OPT const DN_PTR *dnComponentList,
1065  IN_FLAGS( CHECKDN ) const int checkFlags,
1066  OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
1067  CRYPT_ATTRIBUTE_TYPE *errorLocus,
1068  OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
1069  CRYPT_ERRTYPE_TYPE *errorType )
1070  {
1071  DN_COMPONENT *dnComponentListPtr;
1072  BOOLEAN seenCountry = FALSE, seenCommonName = FALSE;
1073  int iterationCount;
1074 
1075  assert( dnComponentList == NULL || \
1076  isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
1077  assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
1078  assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
1079 
1080  REQUIRES( checkFlags > CHECKDN_FLAG_NONE && \
1081  checkFlags <= CHECKDN_FLAG_MAX );
1082  REQUIRES( dnComponentList == NULL || \
1083  isDNComponentValid( dnComponentList ) );
1084 
1085  /* Perform a special-case check for a null DN */
1086  if( dnComponentList == NULL )
1087  return( CRYPT_ERROR_NOTINITED );
1088 
1089  /* Make sure that certain critical components are present */
1090  for( dnComponentListPtr = ( DN_COMPONENT * ) dnComponentList, \
1091  iterationCount = 0;
1092  dnComponentListPtr != NULL && \
1093  iterationCount < FAILSAFE_ITERATIONS_MED;
1094  dnComponentListPtr = dnComponentListPtr->next, \
1095  iterationCount++ )
1096  {
1097  if( dnComponentListPtr->type == CRYPT_CERTINFO_COUNTRYNAME )
1098  {
1099  if( !checkCountryCode( dnComponentListPtr->value ) )
1100  {
1101  *errorType = CRYPT_ERRTYPE_ATTR_VALUE;
1102  *errorLocus = CRYPT_CERTINFO_COUNTRYNAME;
1103  return( CRYPT_ERROR_INVALID );
1104  }
1105  if( seenCountry )
1106  {
1107  *errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
1108  *errorLocus = CRYPT_CERTINFO_COUNTRYNAME;
1109  return( CRYPT_ERROR_DUPLICATE );
1110  }
1111  seenCountry = TRUE;
1112  }
1113  if( dnComponentListPtr->type == CRYPT_CERTINFO_COMMONNAME )
1114  {
1115  if( ( checkFlags & CHECKDN_FLAG_WELLFORMED ) && seenCommonName )
1116  {
1117  *errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
1118  *errorLocus = CRYPT_CERTINFO_COMMONNAME;
1119  return( CRYPT_ERROR_DUPLICATE );
1120  }
1121  seenCommonName = TRUE;
1122  }
1123 
1124  /* Multi-AVA RDNs are handled more or less arbitrarily by
1125  implementations, we don't allow them if the DN is supposed to
1126  be well-formed */
1127  if( ( checkFlags & CHECKDN_FLAG_WELLFORMED ) && \
1128  ( dnComponentListPtr->flags & DN_FLAG_CONTINUED ) )
1129  {
1130  if( dnComponentListPtr->type >= CRYPT_CERTINFO_FIRST && \
1131  dnComponentListPtr->type <= CRYPT_CERTINFO_LAST )
1132  {
1133  *errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
1134  *errorLocus = dnComponentListPtr->type;
1135  }
1136  return( CRYPT_ERROR_INVALID );
1137  }
1138  }
1139  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
1140  if( ( ( checkFlags & CHECKDN_FLAG_COUNTRY ) && !seenCountry ) || \
1141  ( ( checkFlags & CHECKDN_FLAG_COMMONNAME ) && !seenCommonName ) )
1142  {
1143  *errorType = CRYPT_ERRTYPE_ATTR_ABSENT;
1144  *errorLocus = ( seenCountry ) ? CRYPT_CERTINFO_COMMONNAME : \
1146  return( CRYPT_ERROR_NOTINITED );
1147  }
1148 
1149  return( CRYPT_OK );
1150  }
1151 
1152 /* Convert a DN component containing a PKCS #9 emailAddress or an RFC 1274
1153  rfc822Mailbox into an rfc822Name */
1154 
1155 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1156 int convertEmail( INOUT CERT_INFO *certInfoPtr,
1157  INOUT DN_PTR **dnComponentListPtrPtr,
1159  {
1160  DN_COMPONENT *emailComponent;
1161  SELECTION_STATE selectionState;
1162  void *certDataPtr;
1163  int status;
1164 
1165  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1166  assert( isWritePtr( dnComponentListPtrPtr, sizeof( DN_COMPONENT ) ) );
1167  assert( *dnComponentListPtrPtr == NULL || \
1168  isWritePtr( *dnComponentListPtrPtr, sizeof( DN_COMPONENT ) ) );
1169 
1170  REQUIRES( altNameType == CRYPT_CERTINFO_SUBJECTALTNAME || \
1171  altNameType == CRYPT_CERTINFO_ISSUERALTNAME );
1172 
1173  /* If there's no PKCS #9 email address present, try for an RFC 1274 one.
1174  If that's not present either, exit */
1175  if( *dnComponentListPtrPtr == NULL )
1176  {
1177  /* If there's an empty DN present, there's nothing to do */
1178  return( CRYPT_OK );
1179  }
1180  emailComponent = findDNComponentByOID( *dnComponentListPtrPtr,
1181  MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01" ), 11 );
1182  if( emailComponent == NULL )
1183  {
1184  emailComponent = findDNComponentByOID( *dnComponentListPtrPtr,
1185  MKOID( "\x06\x09\x09\x92\x26\x89\x93\xF2\x2C\x01\x03" ), 11 );
1186  }
1187  if( emailComponent == NULL )
1188  return( CRYPT_OK );
1189 
1190  /* Try and add the email address component as an rfc822Name. Since this
1191  changes the current GeneralName selection we have to be careful about
1192  saving and restoring the state. In addition since we're changing the
1193  internal state of an object which is technically in the high state we
1194  have to temporarily disconnect the certificate data from the
1195  certificate object to make it appear as a mutable object. This is an
1196  unfortunate consequence of the fact that what we're doing is a
1197  behind-the-scenes switch to move an initialised certificate component
1198  from where it is to where it really should be */
1199  saveSelectionState( selectionState, certInfoPtr );
1200  certDataPtr = certInfoPtr->certificate;
1201  certInfoPtr->certificate = NULL;
1202  status = addCertComponent( certInfoPtr, CRYPT_ATTRIBUTE_CURRENT,
1203  altNameType );
1204  assert( cryptStatusOK( status ) ); /* Should never fail, warn in debug mode */
1205  if( cryptStatusOK( status ) )
1206  {
1207  status = addCertComponentString( certInfoPtr,
1209  emailComponent->value,
1210  emailComponent->valueLength );
1211  }
1212  if( cryptStatusOK( status ) )
1213  {
1214  /* It was successfully copied over, delete the copy in the DN */
1215  ( void ) deleteComponent( ( DN_COMPONENT ** ) dnComponentListPtrPtr,
1216  emailComponent );
1217  }
1218  else
1219  {
1220  /* If it's already present (which is somewhat odd since the presence
1221  of an email address in the DN implies that the implementation
1222  doesn't know about rfc822Name), we can't do anything about it */
1223  if( status == CRYPT_ERROR_INITED )
1224  status = CRYPT_OK;
1225  else
1226  {
1227  /* Some certificates can contain garbage in the (supposed) email
1228  address, normally the certificate would be rejected because
1229  of this but if we're running in oblivious mode we can import
1230  it successfully but then get an internal error code when we
1231  try and perform this sideways add. To catch this we check
1232  for invalid email addresses here and ignore an error status
1233  if we get one */
1234  if( cryptArgError( status ) )
1235  status = CRYPT_OK;
1236  }
1237  }
1238  certInfoPtr->certificate = certDataPtr;
1239  restoreSelectionState( selectionState, certInfoPtr );
1240 
1241  return( status );
1242  }
1243 #endif /* USE_CERTIFICATES */