1 /****************************************************************************
2 *																			*
3 *					Certificate Attribute Routines Header File 				*
4 *						Copyright Peter Gutmann 1997-2011					*
5 *																			*
6 ****************************************************************************/
7 
8 #ifndef _CERTATTR_DEFINED
9 
10 #define _CERTATTR_DEFINED
11 
12 /****************************************************************************
13 *																			*
14 *								Type Information Flags						*
15 *																			*
16 ****************************************************************************/
17 
18 /* The attribute type information.  This is used to both check the validity
19    of encoded attribute data and to describe the structure of an attribute
20    when encoding it.
21 
22    The flags are broken down into the following groups:
23 
24 	Attribute-specific flags that apply to an individual field or an
25 	overall attribute.
26 
27 	SET/SEQUENCE control flags that indicate the end of a SET/SEQUENCE or
28 	nested SET/SEQUENCE.  These are only used for encoding, for decoding the
29 	decoder maintains a parse state stack driven by the encoded data
30 	(actually that's not quite correct, when skipping to the end of some
31 	SEQUENCEs containing type-and-value pairs we also use the flags to locate
32 	the end of the SEQUENCE encoding/start of the next type-and-value entry).
33 	The use of SEQEND gets extremely complicated in the presence of optional
34 	nested SEQUENCEs because it's not certain how many levels we need to
35 	undo.  Consider for example name constraints:
36 
37 		SEQUENCE {
38 			permittedSubtrees	[ 0 ] SEQUENCE OF {
39 				SEQUENCE { GeneralName }
40 				} OPTIONAL,
41 			excludedSubtrees	[ 1 ] SEQUENCE OF {
42 				SEQUENCE { GeneralName }
43 				} OPTIONAL,
44 			}
45 
46 	Is the value at the end FL_SEQEND or FL_SEQEND_3?  If excludedSubtrees
47 	are absent then it's FL_SEQEND but if we're encoding the excluded
48 	subtree then it's FL_SEQEND_3.  Because of this ambiguity the current
49 	encoding routines simply assume that once they reach the end of an
50 	extension there's an implicit FL_SEQEND_whatever there.  Luckily all of
51 	the ambiguous decoding-level points occur at the end of extensions so
52 	this is a workable way to handle things.
53 
54 	Decoding level flags that indicate the compliance level at which this
55 	attribute is decoded.
56 
57 	The object subtypes for which an attribute is valid.  CRLs actually
58 	contain two sets of extensions, one for the entire CRL (crlExtensions)
59 	and the other for each entry in the CRL (crlEntryExtension).  Sorting
60 	out whether we're adding a CRL extension or per-entry extension is
61 	handled by the higher-level code which references the CRL attribute list
62 	or per-entry attribute list as appropriate.
63 
64    The total-attribute flags are:
65 
66 	FL_ATTR_ATTRSTART/FL_ATTR_ATTREND: Marks the start and end of an
67 		attribute.  This has to be done explicitly because there's no other
68 		field or flag that we can guarantee will always be set for the first
69 		or last field in an attribute and never for any other field.
70 
71 	FL_ATTR_NOCOPY: The attribute is regarded as sensitive and therefore
72 		shouldn't be copied from source to destination (e.g. from a
73 		certificate request into a certificate) when the other attributes
74 		are copied.
75 
76 	FL_ATTR_CRITICAL: The overall extension is marked critical when encoding.
77 
78    The encoding flags are:
79 
80 	FL_DEFAULT: The field has a default value that's set if no field data
81 		is present.
82 
83 	FL_EXPLICIT: The field is explicitly tagged so instead of being en/
84 		decoded using the tag for the field it's given a second level of
85 		tagging that encapsulates the field's actual tag type.
86 
87 	FL_IDENTIFIER: Used to mark the encapsulating SEQUENCE in fields of the
88 		type:
89 
90 		SEQUENCE {
91 			identifier	OBJECT IDENTIFIER
92 			data		ANY DEFINED BY identifier
93 			}
94 
95 		for which the field identified by a CRYPT_CERTINFO_xxx is the 'data'
96 		field and the whole is only encoded if the data field is present.
97 
98 	FL_MULTIVALUED: If a cryptlib-level attribute is part of a SET OF x/
99 		SEQUENCE OF x then this flag is set to indicate that more than one
100 		instance can exist at the same time.  If this flag isn't set then
101 		cryptlib will detect that an attribute of that type already exists
102 		and refuse to allow a second instance to be added.
103 
104 	FL_EMPTYOK: Used for a SET/SEQUENCE consisting of nothing but OPTIONAL
105 		elements to indicate that it's OK to end up with a zero-length
106 		entry, by default we don't allow an empty SET/SEQUENCE since if the
107 		data didn't match any of the optional elements then the decoder
108 		would get stuck in an endless loop.  At the moment this is OK
109 		because the only time we can have an empty SEQUENCE is for the
110 		basicConstraints extension, which is an entire extension for which
111 		the termination point is easily detected.
112 
113 	FL_NONENCODING: The field is read and written but not associated with
114 		any user data.  This is used for fields such as version numbers that
115 		aren't used for encoding user-supplied data but that must be read and
116 		written when processing an attribute
117 
118 	FL_OPTIONAL: The field is optional.
119 
120 	FL_SETOF: Applied to the encapsulating SET/SEQUENCE of a SET OF x/
121 		SEQUENCE OF x to indicate that one or more inner fields may be
122 		present.  The field marked with FL_SETOF in the encoding/decoding
123 		table is bookmarked, if all of the SET/SEQUENCE data isn't read the
124 		first time through then the decoding table position is restarted
125 		from the bookmark until the SET/SEQUENCE data is exhausted.
126 
127 	FL_SPECIALENCODING: The attribute isn't encoded as part of the standard
128 		attributes but requires special-case encoding.  This exists for use
129 		with certificate requests to indicate that the attribute isn't
130 		encoded encapsulated inside an extensionRequest but as a standalone
131 		attribute, because certificate request attributes are usually
132 		encapsulated inside an extensionRequest wrapper, however occasionally
133 		an attribute needs to be encoded in non-encapsulated form.
134 
135 		In addition this is just as much an attribute flag as an encoding
136 		one since it controls the encoding of an entire attribute, we group
137 		it with the encoding flags mostly because there's no room for
138 		expansion any more in the attribute flags */
139 
140 /* Type information and whole-attribute flags */
141 
142 #define FL_VALID_CERT		0x0001		/* Valid in a certificate */
143 #define FL_VALID_ATTRCERT	0x0002		/* Valid in an attribute cert */
144 #define FL_VALID_CRL		0x0004		/* Valid in a CRL */
145 #define FL_VALID_CERTREQ	0x0008		/* Valid in a cert.request */
146 #define FL_VALID_REVREQ		0x0010		/* Valid in a rev.request */
147 #define FL_VALID_OCSPREQ	0x0010		/* Valid in an OCSP request */
148 #define FL_VALID_OCSPRESP	0x0010		/* Valid in an OCSP response */
149 
150 #define FL_LEVEL_OBLIVIOUS	0x0000		/* Process at oblivious compliance level */
151 #define FL_LEVEL_REDUCED	0x0100		/* Process at reduced compliance level */
152 #define FL_LEVEL_STANDARD	0x0200		/* Process at standard compliance level */
153 #define FL_LEVEL_PKIX_PARTIAL 0x0300	/* Process at partial PKIX compliance level */
154 #define FL_LEVEL_PKIX_FULL	0x0400		/* Process at full PKIX compliance level */
155 
156 #define FL_ATTR_NOCOPY		0x1000		/* Attr.isn't copied when attrs.copied */
157 #define FL_ATTR_CRITICAL	0x2000		/* Extension is marked critical */
158 #define FL_ATTR_ATTRSTART	0x4000		/* Start-of-attribute marker */
159 #define FL_ATTR_ATTREND		0x8000		/* End-of-attribute marker */
160 
161 #define FL_VALID_MASK		0x1F		/* Mask for type-validity value */
162 #define FL_LEVEL_SHIFT		8			/* Shift amount to get into range 0...n */
163 #define FL_LEVEL_MASK		7			/* Mask for compliance level value */
164 
165 /* Encoding flags */
166 
167 #define FL_SEQEND			0x0001		/* End of constructed object */
168 #define FL_SEQEND_2			0x0002		/*  End of cons.obj + one nesting lvl.*/
169 #define FL_SEQEND_3			0x0003		/*  End of cons.obj + two nesting lvls.*/
170 #define FL_SEQEND_4			0x0004		/*  End of cons.obj + three nesting lvls.*/
171 #define FL_SEQEND_5			0x0005		/*  End of cons.obj + four nesting lvls.*/
172 #define FL_SEQEND_6			0x0006		/*  End of cons.obj + four nesting lvls.*/
173 #define FL_SEQEND_7			0x0007		/*  End of cons.obj + four nesting lvls.*/
174 
175 #define FL_SEQEND_MASK		7			/* Mask for sequence control value */
176 
177 #define FL_OPTIONAL			0x0010		/* Field is optional */
178 #define FL_DEFAULT			0x0020		/* Field has default value */
179 #define FL_EXPLICIT			0x0040		/* Field is explicitly tagged */
180 #define FL_IDENTIFIER		0x0080		/* Following field contains selection OID */
181 #define FL_SETOF			0x0100		/* Start of SET/SEQ OF values */
182 #define FL_EMPTYOK			0x0200		/* SET/SEQ may be empty */
183 #define FL_NONENCODING		0x0400		/* Field is a non-encoding value */
184 #define FL_MULTIVALUED		0x0800		/* Field can occur multiple times */
185 #define FL_SPECIALENCODING	0x1000		/* Attribute requires special-case encoding */
186 
187 /* If a constructed field is nested (for example a SEQUENCE OF SEQUENCE)
188    then the FL_SEQEND may need to denote multiple levels of unnesting.  This
189    is done by using FL_SEQEND_n, the following macro can be used to extract
190    the actual level of nesting */
191 
192 #define decodeNestingLevel( value )		( ( value ) & FL_SEQEND_MASK )
193 
194 /* In order to be able to process broken certificates we allow for
195    processing them at various levels of standards compliance.  If the
196    current processing level is below that required for the extension then
197    we skip it and treat it as a blob extension */
198 
199 #define decodeComplianceLevel( value ) \
200 		( ( ( value ) >> FL_LEVEL_SHIFT ) & FL_LEVEL_MASK )
201 
202 /* Usually the field ID for the first field in an entry (the one containing
203    the OID) is the overall attribute ID, however there are one or two
204    exceptions in which the attribute ID and field ID are the same but are
205    given in separate fields (examples of this are the altNames, which have
206    a single field ID SUBJECT/ISSUERALTNAME that applies to the attribute as
207    a whole but also to the one and only field in it.
208 
209    If this happens the field ID for the attribute as a whole is given the
210    value FIELDTYPE_ID_FOLLOWS to indicate that the actual ID is present at a
211    later point, with the first field that isn't a FIELDTYPE_ID_FOLLOWS code
212    being treated as the attribute ID */
213 
214 #define FIELDID_FOLLOWS					CRYPT_XATTRIBUTE_PRIVATE
215 
216 /* Determine whether an attribute information entry represents the start of
217    the attribute */
218 
219 #define isAttributeStart( attributeInfoPtr ) \
220 		( ( attributeInfoPtr )->typeInfoFlags & FL_ATTR_ATTRSTART )
221 
222 /* Determine whether an attribute information entry represents the end of
223    the attribute information table */
224 
225 #define isAttributeTableEnd( attributeInfoPtr ) \
226 		( ( attributeInfoPtr )->oid == NULL && \
227 		  ( attributeInfoPtr )->fieldID == CRYPT_IATTRIBUTE_LAST )
228 
229 /****************************************************************************
230 *																			*
231 *						Special-case Field-encoding Values					*
232 *																			*
233 ****************************************************************************/
234 
235 /* Some fields have an intrinsic value but no explicitly set value (that is,
236    their mere presence communicates the information they are intended to
237    convey but the fields themselves contain no actual data).  This applies
238    for fields that contain OIDs that denote certain things such as
239    certificate policies or key usage.  To denote these identifier fields
240    the field type is set to FIELDTYPE_IDENTIFIER (note that we start the
241    values at -2 rather than -1, which is the CRYPT_ERROR value).  When a
242    field of this type is encountered no data value is recorded but the OID
243    for the field is written to the certificate when the field is encoded.
244    The parentheses are to catch potential erroneous use in an expression */
245 
246 #define FIELDTYPE_IDENTIFIER	-2
247 
248 /* Some fields have no set value (these arise from ANY DEFINED BY
249    definitions) or an opaque value (typically fixed parameters for type-and-
250    value pairs).  To denote these fields the field type is set to
251    FIELDTYPE_BLOB.  However this causes problems with type-checking since
252    now absolutely anything can be passed in as valid data.  To allow at
253    least some type-checking we provide a hint as to the general encoding of
254    the blob, which can be one of SEQUENCE, BIT STRING, or a genuine blob
255    used in ANY DEFINED BY constructions, for which we can at least check
256    that it's some sort of ASN.1 object.  There are also two cases in which
257    an ANY blob is used where it'd be possible to use more specific blobs
258    for OBJECT IDENTIFIERs and GeneralNames and that's in { OID, value }
259    selection lists in which the ANY blob acts spefically as an end-of-
260    list marker as well as being just a catchall type */
261 
262 #define FIELDTYPE_BLOB_ANY		-3
263 #define FIELDTYPE_BLOB_BITSTRING -4
264 #define FIELDTYPE_BLOB_SEQUENCE	-5
265 
266 /* When a field contains a CHOICE it can contain any one of the CHOICE
267    fields, as opposed to a FL_SETOF which can contain any of the fields that
268    follow it.  Currently the only CHOICE fields contain OIDs as choices, the
269    CHOICE fieldtype indicates that the value is stored in the field itself
270    but the encoding is handled via a separate encoding table pointed to by
271    extraData that maps the value to an OID */
272 
273 #define FIELDTYPE_CHOICE		-6
274 
275 /* Some fields are composite fields that contain complete certificate data
276    structures.  To denote these fields the field type is a special code that
277    specifies the type and the value member contains the handle or the data
278    member contains a pointer to the composite object */
279 
280 #define FIELDTYPE_DN			-7
281 
282 /* As an extension of the above, some fields are complex enough to require
283    complete alternative encoding tables.  The most obvious one is
284    GeneralName but this is also used for some CHOICE types where the value
285    selects a particular OID or entry from an alternative encoding table.  In
286    this case the extraData member is a pointer to the alternative encoding
287    table */
288 
289 #define FIELDTYPE_SUBTYPED		-8
290 
291 /* Another variant of FIELDTYPE_DN is one where the field can contain one of
292    a number of string types chosen from the ASN.1 string menagerie.  The two
293    main classes that seem to be popular in standards are the DirectoryString,
294    { BMPString | PrintableString | TeletexString | UniversalString |
295      UTF8String } and DisplayText, { BMPString | IA5String | UTF8String |
296 	 VisibleString }.  Rather than adding a list of the different string
297    types all marked as optional to the en/decoding tables (so that the
298    decoder stops whenever it reaches the one that matches the string value
299    being decoded) we provide a single TextString meta-type which has a
300    custom decoding routine that makes the appropriate choice between the
301    union of all of the above types */
302 
303 #define FIELDTYPE_TEXTSTRING	-9
304 
305 /* The last possible field type */
306 
307 #define FIELDTYPE_LAST			FIELDTYPE_TEXTSTRING
308 
309 /* Since there are multiple blob fields (due to the use of typing hints) we
310    need a macro to determine whether a field is a blob of any form.  The
311    odd-looking range comparison below is because the fields have negative
312    values */
313 
314 #define isBlobField( field ) \
315 		( ( field ) <= FIELDTYPE_BLOB_ANY && \
316 		  ( field ) >= FIELDTYPE_BLOB_SEQUENCE )
317 
318 /****************************************************************************
319 *																			*
320 *							Attribute Data Structures						*
321 *																			*
322 ****************************************************************************/
323 
324 /* The structure to store en/decoding information for an attribute field */
325 
326 typedef struct {
327 	/* Information on the overall attribute.  These fields are only set
328 	   for overall attribute definitions */
329 	const BYTE FAR_BSS *oid;		/* OID for this attribute */
330 
331 	/* Information on this particular field in the attribute.  The fieldID
332 	   is the attribute type for this field or one of the FIELDTYPE_xxx
333 	   codes defined above, the fieldType is the field as defined (e.g.
334 	   SEQUENCE, INTEGER), the fieldEncodingType is the field as encoded: 0
335 	   if it's the same as the field type or the tag if it's a tagged field.
336 	   The default tagging is to use implicit tags (e.g. [ 0 ] IMPLICIT
337 	   SEQUENCE) with a field of type fieldType and encoding of type
338 	   fieldEncodedType.  If FL_EXPLICIT is set then it's an explicitly
339 	   tagged field and both fields are used for the encoding */
340 	const CRYPT_ATTRIBUTE_TYPE fieldID;	/* Magic ID for this field */
341 #ifndef NDEBUG
342 	const char *description;		/* Text description */
343 #endif /* NDEBUG */
344 	const int fieldType;			/* ASN.1 tag/type for this field */
345 	const int fieldEncodedType;		/* ASN.1 tag for field as encoded */
346 
347 	/* General status information */
348 	const int typeInfoFlags;		/* Attribute-processing */
349 	const int encodingFlags;		/* Encoding flags */
350 
351 	/* Information to allow validity checking for this field */
352 	const int lowRange;				/* Min/max allowed if numeric/boolean */
353 	const int highRange;			/* Min/max length if string */
354 	const int defaultValue;			/* Default value if FL_DEFAULT set,
355 									   length if FIELDTYPE_BLOB */
356 
357 	/* Extra data needed to process this field, either a pointer to an
358 	   alternative encoding table or a pointer to the validation function to
359 	   allow extended validity checking */
360 	const void *extraData;
361 	} ATTRIBUTE_INFO;
362 
363 /* When building the debug version of the code we include a text string
364    describing the field which is being processed, this makes it easier to
365    track down the point in a certificate where cryptlib finds a problem */
366 
367 #ifndef NDEBUG
368   #define DESCRIPTION( text )		text,
369 #else
370   #define DESCRIPTION( text )
371 #endif /* NDEBUG */
372 
373 /* Attribute information flags.  These are:
374 
375 	FLAG_BLOB: Disables all type-checking on the field, needed to handle
376 			some certificates that have invalid field encodings.
377 
378 	FLAG_BLOB_PAYLOAD: Disables type checking on the field payload, for
379 			example checking that the chars in the string are valid for the
380 			given ASN.1 string type.
381 
382 	FLAG_CRITICAL: The extension containing the field is marked criticial.
383 
384 	FLAG_DEFAULTVALUE: The field has a value which is equal to the default
385 			for this field, so it doesn't get encoded.  This flag is set
386 			during the encoding pre-processing pass.
387 
388 	FLAG_IGNORED: The field is recognised but was ignored at this compliance
389 			level.  This prevents the certificate from being rejected if the
390 			field is marked critical.
391 
392 	FLAG_LOCKED: The attribute can't be deleted once set, needed to handle
393 			fields that are added internally by cryptlib that shouldn't be
394 			deleted by users once set.
395 
396 	FLAG_MULTIVALUED: Multiple instantiations of this field are allowed */
397 
398 #define ATTR_FLAG_NONE			0x0000	/* No flag */
399 #define ATTR_FLAG_CRITICAL		0x0001	/* Critical cert extension */
400 #define ATTR_FLAG_LOCKED		0x0002	/* Field can't be modified */
401 #define ATTR_FLAG_BLOB			0x0004	/* Non-type-checked blob data */
402 #define ATTR_FLAG_BLOB_PAYLOAD	0x0008	/* Payload is non-type-checked blob data */
403 #define ATTR_FLAG_MULTIVALUED	0x0010	/* Multiple instances allowed */
404 #define ATTR_FLAG_DEFAULTVALUE	0x0020	/* Field has default value */
405 #define ATTR_FLAG_IGNORED		0x0040	/* Attribute ignored at this compl.level */
406 #define ATTR_FLAG_MAX			0x007F	/* Maximum possible flag value */
407 
408 /* When comparing attribute fields we only want to compare relevant data and
409    not incidental flags related to parsing or encoding actions.  The following
410    mask defines the attribute flags that we want to compare */
411 
412 #define ATTR_FLAGS_COMPARE_MASK	( ATTR_FLAG_CRITICAL )
413 
414 /* The structure to hold a field of a certificate attribute */
415 
416 typedef struct AL {
417 	/* Identification and encoding information for this attribute field or
418 	   attribute.  This consists of the field ID for the attribute as a
419 	   whole (e.g. CRYPT_CERTINFO_NAMECONSTRAINTS), for the attribute field
420 	   (that is, one field of a full attribute, e.g.
421 	   CRYPT_CERTINFO_EXCLUDEDSUBTREES) and for the subfield of the attribute
422 	   field in the case of composite fields like GeneralNames, a pointer to
423 	   the sync point used when encoding the attribute, and the encoded size
424 	   of this field.  If it's a special-case attribute field such as a blob
425 	   field or a field with a fixed default value that's present only for
426 	   encoding purposes then the attributeID and fieldID are set to special
427 	   values decoded by the isXXX() macros further down.  The subFieldID is
428 	   only set if the fieldID is for a GeneralName field.
429 
430 	   Although the field type information is contained in the
431 	   attributeInfoPtr it's sometimes needed before this has been set up
432 	   to handle special formatting requirements, for example to enable
433 	   special-case handling for a DN attribute field or to specify that an
434 	   OID needs to be decoded into its string representation before being
435 	   returned to the caller.  Because of this we store a copy of the field
436 	   type information here to allow for this special processing */
437 	CRYPT_ATTRIBUTE_TYPE attributeID;/* Attribute ID */
438 	CRYPT_ATTRIBUTE_TYPE fieldID;	/* Attribute field ID */
439 	CRYPT_ATTRIBUTE_TYPE subFieldID;	/* Attribute subfield ID */
440 	const ATTRIBUTE_INFO *attributeInfoPtr;	/* Pointer to encoding sync point */
441 	int encodedSize;				/* Encoded size of this field */
442 	int fieldType;					/* Attribute field type */
443 	int flags;						/* Flags for this field */
444 
445 	/* Sometimes a field is part of a constructed object or even a nested
446 	   series of constructed objects (these are always SEQUENCEs).  Since
447 	   this is purely an encoding issue there are no attribute list entries
448 	   for the SEQUENCE fields so when we perform the first pass over the
449 	   attribute list prior to encoding we remember the lengths of the
450 	   SEQUENCEs for later use.  Since we can have nested SEQUENCEs
451 	   containing a given field we store the lengths and pointers to the
452 	   ATTRIBUTE_INFO table entries used to encode them in a fifo with the
453 	   innermost one first and successive outer ones following it */
454 	ARRAY( ENCODING_FIFO_SIZE, fifoPos ) \
455 	int sizeFifo[ ENCODING_FIFO_SIZE + 2 ];
456 									/* Encoded size of SEQUENCE containing
457 									   this field, if present */
458 	ARRAY( ENCODING_FIFO_SIZE, fifoPos ) \
459 	const ATTRIBUTE_INFO *encodingFifo[ ENCODING_FIFO_SIZE + 2 ];
460 									/* Encoding table entry used to encode
461 									   this SEQUENCE */
462 	int fifoEnd;					/* End of list of SEQUENCE sizes */
463 	int fifoPos;					/* Current position in list */
464 
465 	/* The data payload for this attribute field or attribute.  If it's
466 	   numeric data such as a simple boolean, bitstring, or small integer,
467 	   we store it in the intValue member.  If it's an OID or some form of
468 	   string we store it in the variable-length buffer */
469 	long intValue;					/* Integer value for simple types */
470 	BUFFER_OPT_FIXED( valueLength ) \
471 	void *value;					/* Attribute value */
472 	int valueLength;				/* Attribute value length */
473 
474 	/* The OID, for blob-type attributes */
475 	BYTE *oid;						/* Attribute OID */
476 
477 	/* The previous and next list element in the linked list of elements */
478 	struct AL *prev, *next;
479 
480 	/* Variable-length storage for the attribute data */
481 	DECLARE_VARSTRUCT_VARS;
482 	} ATTRIBUTE_LIST;
483 
484 /****************************************************************************
485 *																			*
486 *								Attribute Functions							*
487 *																			*
488 ****************************************************************************/
489 
490 /* The validation function used to perform additional validation on fields */
491 
492 typedef CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
493 		int ( *VALIDATION_FUNCTION )( const ATTRIBUTE_LIST *attributeListPtr );
494 
495 /* Look up an ATTRIBUTE_INFO entry based on an OID */
496 
497 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
498 const ATTRIBUTE_INFO *oidToAttribute( IN_ENUM( ATTRIBUTE ) \
499 										const ATTRIBUTE_TYPE attributeType,
500 									  IN_BUFFER( oidLength ) const BYTE *oid,
501 									  IN_LENGTH_OID const int oidLength );
502 
503 /* Select the appropriate attribute info table for encoding/type checking */
504 
505 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
506 int getAttributeInfo( IN_ENUM( ATTRIBUTE ) const ATTRIBUTE_TYPE attributeType,
507 					  OUT const ATTRIBUTE_INFO **attributeInfoPtrPtr,
508 					  OUT_INT_Z int *noAttributeEntries );
509 
510 /* Get the encoded tag for a field */
511 
512 CHECK_RETVAL_RANGE( MAKE_CTAG_PRIMITIVE( 0 ), MAX_TAG ) STDC_NONNULL_ARG( ( 1 ) ) \
513 int getFieldEncodedTag( const ATTRIBUTE_INFO *attributeInfoPtr );
514 
515 /* Get the attribute and attributeID for a field ID */
516 
517 CHECK_RETVAL_PTR \
518 const ATTRIBUTE_INFO *fieldIDToAttribute( IN_ENUM( ATTRIBUTE ) \
519 											const ATTRIBUTE_TYPE attributeType,
520 										  IN_ATTRIBUTE \
521 											const CRYPT_ATTRIBUTE_TYPE fieldID,
522 										  IN_ATTRIBUTE_OPT \
523 											const CRYPT_ATTRIBUTE_TYPE subFieldID,
524 										  OUT_OPT_ATTRIBUTE_Z \
525 											CRYPT_ATTRIBUTE_TYPE *attributeID );
526 
527 /* Find the start of an attribute from an arbitrary position in an attribute
528    list */
529 
530 CHECK_RETVAL_PTR \
531 ATTRIBUTE_LIST *findAttributeStart( IN_OPT const ATTRIBUTE_LIST *attributeListPtr );
532 
533 /* Write an attribute field */
534 
535 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
536 int writeAttributeField( INOUT_OPT STREAM *stream,
537 						 INOUT ATTRIBUTE_LIST *attributeListPtr,
538 						 IN_RANGE( 0, 4 ) const int complianceLevel );
539 
540 #endif /* _CERTATTR_DEFINED */
541