Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / security / nss / lib / pkcs7 / certread.c
blob31422095327cef3b822fc2aacbb4227d746aa645
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "cert.h"
38 #include "secpkcs7.h"
39 #include "base64.h"
40 #include "secitem.h"
41 #include "secder.h"
42 #include "secasn1.h"
43 #include "secoid.h"
44 #include "secerr.h"
46 SEC_ASN1_MKSUB(SEC_AnyTemplate)
48 SECStatus
49 SEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg)
51 SEC_PKCS7ContentInfo *contentInfo = NULL;
52 SECStatus rv;
53 SECItem **certs;
54 int count;
56 contentInfo = SEC_PKCS7DecodeItem(pkcs7Item, NULL, NULL, NULL, NULL, NULL,
57 NULL, NULL);
58 if ( contentInfo == NULL ) {
59 goto loser;
62 if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_PKCS7_SIGNED_DATA ) {
63 goto loser;
66 certs = contentInfo->content.signedData->rawCerts;
67 if ( certs ) {
68 count = 0;
70 while ( *certs ) {
71 count++;
72 certs++;
74 rv = (* f)(arg, contentInfo->content.signedData->rawCerts, count);
77 rv = SECSuccess;
79 goto done;
80 loser:
81 rv = SECFailure;
83 done:
84 if ( contentInfo ) {
85 SEC_PKCS7DestroyContentInfo(contentInfo);
88 return(rv);
91 const SEC_ASN1Template SEC_CertSequenceTemplate[] = {
92 { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
95 SECStatus
96 SEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg)
98 SECStatus rv;
99 SECItem **certs;
100 int count;
101 SECItem **rawCerts = NULL;
102 PRArenaPool *arena;
103 SEC_PKCS7ContentInfo *contentInfo = NULL;
105 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
106 if (arena == NULL) {
107 return SECFailure;
110 contentInfo = SEC_PKCS7DecodeItem(certsItem, NULL, NULL, NULL, NULL, NULL,
111 NULL, NULL);
112 if ( contentInfo == NULL ) {
113 goto loser;
116 if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE ) {
117 goto loser;
121 rv = SEC_QuickDERDecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate,
122 contentInfo->content.data);
124 if (rv != SECSuccess) {
125 goto loser;
128 certs = rawCerts;
129 if ( certs ) {
130 count = 0;
132 while ( *certs ) {
133 count++;
134 certs++;
136 rv = (* f)(arg, rawCerts, count);
139 rv = SECSuccess;
141 goto done;
142 loser:
143 rv = SECFailure;
145 done:
146 if ( contentInfo ) {
147 SEC_PKCS7DestroyContentInfo(contentInfo);
150 if ( arena ) {
151 PORT_FreeArena(arena, PR_FALSE);
154 return(rv);
157 CERTCertificate *
158 CERT_ConvertAndDecodeCertificate(char *certstr)
160 CERTCertificate *cert;
161 SECStatus rv;
162 SECItem der;
164 rv = ATOB_ConvertAsciiToItem(&der, certstr);
165 if (rv != SECSuccess)
166 return NULL;
168 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
169 &der, NULL, PR_FALSE, PR_TRUE);
171 PORT_Free(der.data);
172 return cert;
175 static const char NS_CERT_HEADER[] = "-----BEGIN CERTIFICATE-----";
176 static const char NS_CERT_TRAILER[] = "-----END CERTIFICATE-----";
177 #define NS_CERT_HEADER_LEN ((sizeof NS_CERT_HEADER) - 1)
178 #define NS_CERT_TRAILER_LEN ((sizeof NS_CERT_TRAILER) - 1)
180 static const char CERTIFICATE_TYPE_STRING[] = "certificate";
181 #define CERTIFICATE_TYPE_LEN (sizeof(CERTIFICATE_TYPE_STRING)-1)
184 * read an old style ascii or binary certificate chain
186 SECStatus
187 CERT_DecodeCertPackage(char *certbuf,
188 int certlen,
189 CERTImportCertificateFunc f,
190 void *arg)
192 unsigned char *cp;
193 unsigned char *bincert = NULL;
194 char * ascCert = NULL;
195 SECStatus rv;
197 if ( certbuf == NULL ) {
198 return(SECFailure);
201 cp = (unsigned char *)certbuf;
203 /* is a DER encoded certificate of some type? */
204 if ( ( *cp & 0x1f ) == SEC_ASN1_SEQUENCE ) {
205 SECItem certitem;
206 SECItem *pcertitem = &certitem;
207 int seqLen, seqLenLen;
209 cp++;
211 if ( *cp & 0x80) {
212 /* Multibyte length */
213 seqLenLen = cp[0] & 0x7f;
215 switch (seqLenLen) {
216 case 4:
217 seqLen = ((unsigned long)cp[1]<<24) |
218 ((unsigned long)cp[2]<<16) | (cp[3]<<8) | cp[4];
219 break;
220 case 3:
221 seqLen = ((unsigned long)cp[1]<<16) | (cp[2]<<8) | cp[3];
222 break;
223 case 2:
224 seqLen = (cp[1]<<8) | cp[2];
225 break;
226 case 1:
227 seqLen = cp[1];
228 break;
229 default:
230 /* indefinite length */
231 seqLen = 0;
233 cp += ( seqLenLen + 1 );
235 } else {
236 seqLenLen = 0;
237 seqLen = *cp;
238 cp++;
241 /* check entire length if definite length */
242 if ( seqLen || seqLenLen ) {
243 if ( certlen != ( seqLen + seqLenLen + 2 ) ) {
244 if (certlen > ( seqLen + seqLenLen + 2 ))
245 PORT_SetError(SEC_ERROR_EXTRA_INPUT);
246 else
247 PORT_SetError(SEC_ERROR_INPUT_LEN);
248 goto notder;
252 /* check the type string */
253 /* netscape wrapped DER cert */
254 if ( ( cp[0] == SEC_ASN1_OCTET_STRING ) &&
255 ( cp[1] == CERTIFICATE_TYPE_LEN ) &&
256 ( PORT_Strcmp((char *)&cp[2], CERTIFICATE_TYPE_STRING) ) ) {
258 cp += ( CERTIFICATE_TYPE_LEN + 2 );
260 /* it had better be a certificate by now!! */
261 certitem.data = cp;
262 certitem.len = certlen - ( cp - (unsigned char *)certbuf );
264 rv = (* f)(arg, &pcertitem, 1);
266 return(rv);
267 } else if ( cp[0] == SEC_ASN1_OBJECT_ID ) {
268 SECOidData *oiddata;
269 SECItem oiditem;
270 /* XXX - assume DER encoding of OID len!! */
271 oiditem.len = cp[1];
272 oiditem.data = (unsigned char *)&cp[2];
273 oiddata = SECOID_FindOID(&oiditem);
274 if ( oiddata == NULL ) {
275 return(SECFailure);
278 certitem.data = (unsigned char*)certbuf;
279 certitem.len = certlen;
281 switch ( oiddata->offset ) {
282 case SEC_OID_PKCS7_SIGNED_DATA:
283 return(SEC_ReadPKCS7Certs(&certitem, f, arg));
284 break;
285 case SEC_OID_NS_TYPE_CERT_SEQUENCE:
286 return(SEC_ReadCertSequence(&certitem, f, arg));
287 break;
288 default:
289 break;
292 } else {
293 /* it had better be a certificate by now!! */
294 certitem.data = (unsigned char*)certbuf;
295 certitem.len = certlen;
297 rv = (* f)(arg, &pcertitem, 1);
298 return(rv);
302 /* now look for a netscape base64 ascii encoded cert */
303 notder:
305 unsigned char *certbegin = NULL;
306 unsigned char *certend = NULL;
307 char *pc;
308 int cl;
310 /* Convert the ASCII data into a nul-terminated string */
311 ascCert = (char *)PORT_Alloc(certlen + 1);
312 if (!ascCert) {
313 rv = SECFailure;
314 goto loser;
317 PORT_Memcpy(ascCert, certbuf, certlen);
318 ascCert[certlen] = '\0';
320 pc = PORT_Strchr(ascCert, '\n'); /* find an EOL */
321 if (!pc) { /* maybe this is a MAC file */
322 pc = ascCert;
323 while (*pc && NULL != (pc = PORT_Strchr(pc, '\r'))) {
324 *pc++ = '\n';
328 cp = (unsigned char *)ascCert;
329 cl = certlen;
331 /* find the beginning marker */
332 while ( cl > NS_CERT_HEADER_LEN ) {
333 int found = 0;
334 if ( !PORT_Strncasecmp((char *)cp, NS_CERT_HEADER,
335 NS_CERT_HEADER_LEN) ) {
336 cl -= NS_CERT_HEADER_LEN;
337 cp += NS_CERT_HEADER_LEN;
338 found = 1;
341 /* skip to next eol */
342 while ( cl && ( *cp != '\n' )) {
343 cp++;
344 cl--;
347 /* skip all blank lines */
348 while ( cl && ( *cp == '\n' || *cp == '\r' )) {
349 cp++;
350 cl--;
352 if (cl && found) {
353 certbegin = cp;
354 break;
358 if ( certbegin ) {
359 /* find the ending marker */
360 while ( cl >= NS_CERT_TRAILER_LEN ) {
361 if ( !PORT_Strncasecmp((char *)cp, NS_CERT_TRAILER,
362 NS_CERT_TRAILER_LEN) ) {
363 certend = (unsigned char *)cp;
364 break;
367 /* skip to next eol */
368 while ( cl && ( *cp != '\n' )) {
369 cp++;
370 cl--;
373 /* skip all blank lines */
374 while ( cl && ( *cp == '\n' || *cp == '\r' )) {
375 cp++;
376 cl--;
381 if ( certbegin && certend ) {
382 unsigned int binLen;
384 *certend = 0;
385 /* convert to binary */
386 bincert = ATOB_AsciiToData(certbegin, &binLen);
387 if (!bincert) {
388 rv = SECFailure;
389 goto loser;
392 /* now recurse to decode the binary */
393 rv = CERT_DecodeCertPackage((char *)bincert, binLen, f, arg);
395 } else {
396 PORT_SetError(SEC_ERROR_BAD_DER);
397 rv = SECFailure;
401 loser:
403 if ( bincert ) {
404 PORT_Free(bincert);
407 if ( ascCert ) {
408 PORT_Free(ascCert);
411 return(rv);
414 typedef struct {
415 PRArenaPool *arena;
416 SECItem cert;
417 } collect_args;
419 static SECStatus
420 collect_certs(void *arg, SECItem **certs, int numcerts)
422 SECStatus rv;
423 collect_args *collectArgs;
425 collectArgs = (collect_args *)arg;
427 rv = SECITEM_CopyItem(collectArgs->arena, &collectArgs->cert, *certs);
429 return(rv);
434 * read an old style ascii or binary certificate
436 CERTCertificate *
437 CERT_DecodeCertFromPackage(char *certbuf, int certlen)
439 collect_args collectArgs;
440 SECStatus rv;
441 CERTCertificate *cert = NULL;
443 collectArgs.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
445 rv = CERT_DecodeCertPackage(certbuf, certlen, collect_certs,
446 (void *)&collectArgs);
447 if ( rv == SECSuccess ) {
448 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
449 &collectArgs.cert, NULL,
450 PR_FALSE, PR_TRUE);
453 PORT_FreeArena(collectArgs.arena, PR_FALSE);
455 return(cert);