/src/nss/lib/certdb/xbsconst.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /* This Source Code Form is subject to the terms of the Mozilla Public  | 
2  |  |  * License, v. 2.0. If a copy of the MPL was not distributed with this  | 
3  |  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */  | 
4  |  |  | 
5  |  | /*  | 
6  |  |  * X.509 v3 Basic Constraints Extension  | 
7  |  |  */  | 
8  |  |  | 
9  |  | #include "prtypes.h"  | 
10  |  | #include <limits.h> /* for LONG_MAX */  | 
11  |  | #include "seccomon.h"  | 
12  |  | #include "secdert.h"  | 
13  |  | #include "secoidt.h"  | 
14  |  | #include "secasn1t.h"  | 
15  |  | #include "secasn1.h"  | 
16  |  | #include "certt.h"  | 
17  |  | #include "secder.h"  | 
18  |  | #include "prprf.h"  | 
19  |  | #include "secerr.h"  | 
20  |  |  | 
21  |  | typedef struct EncodedContext { | 
22  |  |     SECItem isCA;  | 
23  |  |     SECItem pathLenConstraint;  | 
24  |  |     SECItem encodedValue;  | 
25  |  |     PLArenaPool *arena;  | 
26  |  | } EncodedContext;  | 
27  |  |  | 
28  |  | static const SEC_ASN1Template CERTBasicConstraintsTemplate[] = { | 
29  |  |     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(EncodedContext) }, | 
30  |  |     { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ | 
31  |  |       offsetof(EncodedContext, isCA) },  | 
32  |  |     { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER, | 
33  |  |       offsetof(EncodedContext, pathLenConstraint) },  | 
34  |  |     { 0 } | 
35  |  | };  | 
36  |  |  | 
37  |  | static unsigned char hexTrue = 0xff;  | 
38  |  | static unsigned char hexFalse = 0x00;  | 
39  |  |  | 
40  |  | #define GEN_BREAK(status) \  | 
41  | 0  |     rv = status;          \  | 
42  | 0  |     break;  | 
43  |  |  | 
44  |  | SECStatus  | 
45  |  | CERT_EncodeBasicConstraintValue(PLArenaPool *arena, CERTBasicConstraints *value,  | 
46  |  |                                 SECItem *encodedValue)  | 
47  | 0  | { | 
48  | 0  |     EncodedContext encodeContext;  | 
49  | 0  |     PLArenaPool *our_pool = NULL;  | 
50  | 0  |     SECStatus rv = SECSuccess;  | 
51  |  | 
  | 
52  | 0  |     do { | 
53  | 0  |         PORT_Memset(&encodeContext, 0, sizeof(encodeContext));  | 
54  | 0  |         if (!value->isCA && value->pathLenConstraint >= 0) { | 
55  | 0  |             PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);  | 
56  | 0  |             GEN_BREAK(SECFailure);  | 
57  | 0  |         }  | 
58  |  |  | 
59  | 0  |         encodeContext.arena = arena;  | 
60  | 0  |         if (value->isCA == PR_TRUE) { | 
61  | 0  |             encodeContext.isCA.data = &hexTrue;  | 
62  | 0  |             encodeContext.isCA.len = 1;  | 
63  | 0  |         }  | 
64  |  |  | 
65  |  |         /* If the pathLenConstraint is less than 0, then it should be  | 
66  |  |          * omitted from the encoding.  | 
67  |  |          */  | 
68  | 0  |         if (value->isCA && value->pathLenConstraint >= 0) { | 
69  | 0  |             our_pool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);  | 
70  | 0  |             if (our_pool == NULL) { | 
71  | 0  |                 PORT_SetError(SEC_ERROR_NO_MEMORY);  | 
72  | 0  |                 GEN_BREAK(SECFailure);  | 
73  | 0  |             }  | 
74  | 0  |             if (SEC_ASN1EncodeUnsignedInteger(  | 
75  | 0  |                     our_pool, &encodeContext.pathLenConstraint,  | 
76  | 0  |                     (unsigned long)value->pathLenConstraint) == NULL) { | 
77  | 0  |                 PORT_SetError(SEC_ERROR_NO_MEMORY);  | 
78  | 0  |                 GEN_BREAK(SECFailure);  | 
79  | 0  |             }  | 
80  | 0  |         }  | 
81  | 0  |         if (SEC_ASN1EncodeItem(arena, encodedValue, &encodeContext,  | 
82  | 0  |                                CERTBasicConstraintsTemplate) == NULL) { | 
83  | 0  |             GEN_BREAK(SECFailure);  | 
84  | 0  |         }  | 
85  | 0  |     } while (0);  | 
86  | 0  |     if (our_pool)  | 
87  | 0  |         PORT_FreeArena(our_pool, PR_FALSE);  | 
88  | 0  |     return (rv);  | 
89  | 0  | }  | 
90  |  |  | 
91  |  | SECStatus  | 
92  |  | CERT_DecodeBasicConstraintValue(CERTBasicConstraints *value,  | 
93  |  |                                 const SECItem *encodedValue)  | 
94  | 0  | { | 
95  | 0  |     EncodedContext decodeContext;  | 
96  | 0  |     PORTCheapArenaPool tmpArena;  | 
97  | 0  |     SECStatus rv = SECSuccess;  | 
98  |  | 
  | 
99  | 0  |     do { | 
100  | 0  |         PORT_Memset(&decodeContext, 0, sizeof(decodeContext));  | 
101  |  |         /* initialize the value just in case we got "0x30 00", or when the  | 
102  |  |            pathLenConstraint is omitted.  | 
103  |  |          */  | 
104  | 0  |         decodeContext.isCA.data = &hexFalse;  | 
105  | 0  |         decodeContext.isCA.len = 1;  | 
106  |  | 
  | 
107  | 0  |         PORT_InitCheapArena(&tmpArena, SEC_ASN1_DEFAULT_ARENA_SIZE);  | 
108  |  | 
  | 
109  | 0  |         rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodeContext,  | 
110  | 0  |                                     CERTBasicConstraintsTemplate, encodedValue);  | 
111  | 0  |         if (rv == SECFailure)  | 
112  | 0  |             break;  | 
113  |  |  | 
114  | 0  |         value->isCA = decodeContext.isCA.data  | 
115  | 0  |                           ? (PRBool)(decodeContext.isCA.data[0] != 0)  | 
116  | 0  |                           : PR_FALSE;  | 
117  | 0  |         if (decodeContext.pathLenConstraint.data == NULL) { | 
118  |  |             /* if the pathLenConstraint is not encoded, and the current setting  | 
119  |  |               is CA, then the pathLenConstraint should be set to a negative  | 
120  |  |               number  | 
121  |  |               for unlimited certificate path.  | 
122  |  |              */  | 
123  | 0  |             if (value->isCA) { | 
124  | 0  |                 value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;  | 
125  | 0  |             } else { | 
126  | 0  |                 value->pathLenConstraint = 0;  | 
127  | 0  |             }  | 
128  | 0  |         } else if (value->isCA) { | 
129  | 0  |             long len = DER_GetInteger(&decodeContext.pathLenConstraint);  | 
130  | 0  |             if (len < 0 || len == LONG_MAX) { | 
131  | 0  |                 PORT_SetError(SEC_ERROR_BAD_DER);  | 
132  | 0  |                 GEN_BREAK(SECFailure);  | 
133  | 0  |             }  | 
134  | 0  |             value->pathLenConstraint = len;  | 
135  | 0  |         } else { | 
136  |  |             /* here we get an error where the subject is not a CA, but  | 
137  |  |                the pathLenConstraint is set */  | 
138  | 0  |             PORT_SetError(SEC_ERROR_BAD_DER);  | 
139  | 0  |             GEN_BREAK(SECFailure);  | 
140  | 0  |             break;  | 
141  | 0  |         }  | 
142  | 0  |     } while (0);  | 
143  |  |  | 
144  | 0  |     PORT_DestroyCheapArena(&tmpArena);  | 
145  | 0  |     return (rv);  | 
146  | 0  | }  |