Coverage Report

Created: 2025-07-04 06:19

/src/nss/lib/certhigh/certreq.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
#include "cert.h"
6
#include "certt.h"
7
#include "secder.h"
8
#include "keyhi.h"
9
#include "secitem.h"
10
#include "secasn1.h"
11
#include "secerr.h"
12
13
SEC_ASN1_MKSUB(SEC_AnyTemplate)
14
15
const SEC_ASN1Template CERT_AttributeTemplate[] = {
16
    { SEC_ASN1_SEQUENCE,
17
      0, NULL, sizeof(CERTAttribute) },
18
    { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
19
    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(CERTAttribute, attrValue),
20
      SEC_ASN1_SUB(SEC_AnyTemplate) },
21
    { 0 }
22
};
23
24
const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
25
    { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
26
};
27
28
const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
29
    { SEC_ASN1_SEQUENCE,
30
      0, NULL, sizeof(CERTCertificateRequest) },
31
    { SEC_ASN1_INTEGER,
32
      offsetof(CERTCertificateRequest, version) },
33
    { SEC_ASN1_INLINE,
34
      offsetof(CERTCertificateRequest, subject),
35
      CERT_NameTemplate },
36
    { SEC_ASN1_INLINE,
37
      offsetof(CERTCertificateRequest, subjectPublicKeyInfo),
38
      CERT_SubjectPublicKeyInfoTemplate },
39
    { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
40
      offsetof(CERTCertificateRequest, attributes),
41
      CERT_SetOfAttributeTemplate },
42
    { 0 }
43
};
44
45
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
46
47
CERTCertificate *
48
CERT_CreateCertificate(unsigned long serialNumber,
49
                       CERTName *issuer,
50
                       CERTValidity *validity,
51
                       CERTCertificateRequest *req)
52
0
{
53
0
    CERTCertificate *c;
54
0
    int rv;
55
0
    PLArenaPool *arena;
56
57
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
58
59
0
    if (!arena) {
60
0
        return (0);
61
0
    }
62
63
0
    c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
64
65
0
    if (!c) {
66
0
        PORT_FreeArena(arena, PR_FALSE);
67
0
        return 0;
68
0
    }
69
70
0
    c->referenceCount = 1;
71
0
    c->arena = arena;
72
73
    /*
74
     * Default is a plain version 1.
75
     * If extensions are added, it will get changed as appropriate.
76
     */
77
0
    rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
78
0
    if (rv)
79
0
        goto loser;
80
81
0
    rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
82
0
    if (rv)
83
0
        goto loser;
84
85
0
    rv = CERT_CopyName(arena, &c->issuer, issuer);
86
0
    if (rv)
87
0
        goto loser;
88
89
0
    rv = CERT_CopyValidity(arena, &c->validity, validity);
90
0
    if (rv)
91
0
        goto loser;
92
93
0
    rv = CERT_CopyName(arena, &c->subject, &req->subject);
94
0
    if (rv)
95
0
        goto loser;
96
0
    rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
97
0
                                         &req->subjectPublicKeyInfo);
98
0
    if (rv)
99
0
        goto loser;
100
101
0
    return c;
102
103
0
loser:
104
0
    CERT_DestroyCertificate(c);
105
0
    return 0;
106
0
}
107
108
/************************************************************************/
109
/* It's clear from the comments that the original author of this
110
 * function expected the template for certificate requests to treat
111
 * the attributes as a SET OF ANY.  This function expected to be
112
 * passed an array of SECItems each of which contained an already encoded
113
 * Attribute.  But the cert request template does not treat the
114
 * Attributes as a SET OF ANY, and AFAIK never has.  Instead the template
115
 * encodes attributes as a SET OF xxxxxxx.  That is, it expects to encode
116
 * each of the Attributes, not have them pre-encoded.  Consequently an
117
 * array of SECItems containing encoded Attributes is of no value to this
118
 * function.  But we cannot change the signature of this public function.
119
 * It must continue to take SECItems.
120
 *
121
 * I have recoded this function so that each SECItem contains an
122
 * encoded cert extension.  The encoded cert extensions form the list for the
123
 * single attribute of the cert request. In this implementation there is at most
124
 * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
125
 */
126
127
CERTCertificateRequest *
128
CERT_CreateCertificateRequest(CERTName *subject,
129
                              CERTSubjectPublicKeyInfo *spki,
130
                              SECItem **attributes)
131
0
{
132
0
    CERTCertificateRequest *certreq;
133
0
    PLArenaPool *arena;
134
0
    CERTAttribute *attribute;
135
0
    SECOidData *oidData;
136
0
    SECStatus rv;
137
0
    int i = 0;
138
139
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
140
0
    if (arena == NULL) {
141
0
        return NULL;
142
0
    }
143
144
0
    certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
145
0
    if (!certreq) {
146
0
        PORT_FreeArena(arena, PR_FALSE);
147
0
        return NULL;
148
0
    }
149
    /* below here it is safe to goto loser */
150
151
0
    certreq->arena = arena;
152
153
0
    rv = DER_SetUInteger(arena, &certreq->version,
154
0
                         SEC_CERTIFICATE_REQUEST_VERSION);
155
0
    if (rv != SECSuccess)
156
0
        goto loser;
157
158
0
    rv = CERT_CopyName(arena, &certreq->subject, subject);
159
0
    if (rv != SECSuccess)
160
0
        goto loser;
161
162
0
    rv = SECKEY_CopySubjectPublicKeyInfo(arena,
163
0
                                         &certreq->subjectPublicKeyInfo,
164
0
                                         spki);
165
0
    if (rv != SECSuccess)
166
0
        goto loser;
167
168
0
    certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute *, 2);
169
0
    if (!certreq->attributes)
170
0
        goto loser;
171
172
    /* Copy over attribute information */
173
0
    if (!attributes || !attributes[0]) {
174
        /*
175
         ** Invent empty attribute information. According to the
176
         ** pkcs#10 spec, attributes has this ASN.1 type:
177
         **
178
         ** attributes [0] IMPLICIT Attributes
179
         **
180
         ** Which means, we should create a NULL terminated list
181
         ** with the first entry being NULL;
182
         */
183
0
        certreq->attributes[0] = NULL;
184
0
        return certreq;
185
0
    }
186
187
    /* allocate space for attributes */
188
0
    attribute = PORT_ArenaZNew(arena, CERTAttribute);
189
0
    if (!attribute)
190
0
        goto loser;
191
192
0
    oidData = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
193
0
    PORT_Assert(oidData);
194
0
    if (!oidData)
195
0
        goto loser;
196
0
    rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
197
0
    if (rv != SECSuccess)
198
0
        goto loser;
199
200
0
    for (i = 0; attributes[i] != NULL; i++)
201
0
        ;
202
0
    attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i + 1);
203
0
    if (!attribute->attrValue)
204
0
        goto loser;
205
206
    /* copy attributes */
207
0
    for (i = 0; attributes[i]; i++) {
208
        /*
209
        ** Attributes are a SetOf Attribute which implies
210
        ** lexigraphical ordering.  It is assumes that the
211
        ** attributes are passed in sorted.  If we need to
212
        ** add functionality to sort them, there is an
213
        ** example in the PKCS 7 code.
214
        */
215
0
        attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
216
0
        if (!attribute->attrValue[i])
217
0
            goto loser;
218
0
    }
219
220
0
    certreq->attributes[0] = attribute;
221
222
0
    return certreq;
223
224
0
loser:
225
0
    CERT_DestroyCertificateRequest(certreq);
226
0
    return NULL;
227
0
}
228
229
void
230
CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
231
0
{
232
0
    if (req && req->arena) {
233
0
        PORT_FreeArena(req->arena, PR_FALSE);
234
0
    }
235
0
    return;
236
0
}
237
238
static void
239
setCRExt(void *o, CERTCertExtension **exts)
240
0
{
241
0
    ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
242
0
}
243
244
/*
245
** Set up to start gathering cert extensions for a cert request.
246
** The list is created as CertExtensions and converted to an
247
** attribute list by CERT_FinishCRAttributes().
248
*/
249
extern void *cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
250
                                  void (*setExts)(void *object, CERTCertExtension **exts));
251
void *
252
CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
253
0
{
254
0
    return (cert_StartExtensions((void *)req, req->arena, setCRExt));
255
0
}
256
257
/*
258
** At entry req->attributes actually contains an list of cert extensions--
259
** req-attributes is overloaded until the list is DER encoded (the first
260
** ...EncodeItem() below).
261
** We turn this into an attribute list by encapsulating it
262
** in a PKCS 10 Attribute structure
263
*/
264
SECStatus
265
CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
266
0
{
267
0
    SECItem *extlist;
268
0
    SECOidData *oidrec;
269
0
    CERTAttribute *attribute;
270
271
0
    if (!req || !req->arena) {
272
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
273
0
        return SECFailure;
274
0
    }
275
0
    if (req->attributes == NULL || req->attributes[0] == NULL)
276
0
        return SECSuccess;
277
278
0
    extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
279
0
                                 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
280
0
    if (extlist == NULL)
281
0
        return (SECFailure);
282
283
0
    oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
284
0
    if (oidrec == NULL)
285
0
        return SECFailure;
286
287
    /* now change the list of cert extensions into a list of attributes
288
     */
289
0
    req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute *, 2);
290
291
0
    attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
292
293
0
    if (req->attributes == NULL || attribute == NULL ||
294
0
        SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
295
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
296
0
        return SECFailure;
297
0
    }
298
0
    attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem *, 2);
299
300
0
    if (attribute->attrValue == NULL)
301
0
        return SECFailure;
302
303
0
    attribute->attrValue[0] = extlist;
304
0
    attribute->attrValue[1] = NULL;
305
0
    req->attributes[0] = attribute;
306
0
    req->attributes[1] = NULL;
307
308
0
    return SECSuccess;
309
0
}
310
311
SECStatus
312
CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
313
                                     CERTCertExtension ***exts)
314
0
{
315
0
    if (req == NULL || exts == NULL) {
316
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
317
0
        return SECFailure;
318
0
    }
319
320
0
    if (req->attributes == NULL || *req->attributes == NULL)
321
0
        return SECSuccess;
322
323
0
    if ((*req->attributes)->attrValue == NULL) {
324
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
325
0
        return SECFailure;
326
0
    }
327
328
0
    return (SEC_ASN1DecodeItem(req->arena, exts,
329
0
                               SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
330
0
                               (*req->attributes)->attrValue[0]));
331
0
}