source: frontend/node_modules/node-forge/lib/x509.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 99.7 KB
Line 
1/**
2 * Javascript implementation of X.509 and related components (such as
3 * Certification Signing Requests) of a Public Key Infrastructure.
4 *
5 * @author Dave Longley
6 *
7 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
8 *
9 * The ASN.1 representation of an X.509v3 certificate is as follows
10 * (see RFC 2459):
11 *
12 * Certificate ::= SEQUENCE {
13 * tbsCertificate TBSCertificate,
14 * signatureAlgorithm AlgorithmIdentifier,
15 * signatureValue BIT STRING
16 * }
17 *
18 * TBSCertificate ::= SEQUENCE {
19 * version [0] EXPLICIT Version DEFAULT v1,
20 * serialNumber CertificateSerialNumber,
21 * signature AlgorithmIdentifier,
22 * issuer Name,
23 * validity Validity,
24 * subject Name,
25 * subjectPublicKeyInfo SubjectPublicKeyInfo,
26 * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
27 * -- If present, version shall be v2 or v3
28 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
29 * -- If present, version shall be v2 or v3
30 * extensions [3] EXPLICIT Extensions OPTIONAL
31 * -- If present, version shall be v3
32 * }
33 *
34 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
35 *
36 * CertificateSerialNumber ::= INTEGER
37 *
38 * Name ::= CHOICE {
39 * // only one possible choice for now
40 * RDNSequence
41 * }
42 *
43 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
44 *
45 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
46 *
47 * AttributeTypeAndValue ::= SEQUENCE {
48 * type AttributeType,
49 * value AttributeValue
50 * }
51 * AttributeType ::= OBJECT IDENTIFIER
52 * AttributeValue ::= ANY DEFINED BY AttributeType
53 *
54 * Validity ::= SEQUENCE {
55 * notBefore Time,
56 * notAfter Time
57 * }
58 *
59 * Time ::= CHOICE {
60 * utcTime UTCTime,
61 * generalTime GeneralizedTime
62 * }
63 *
64 * UniqueIdentifier ::= BIT STRING
65 *
66 * SubjectPublicKeyInfo ::= SEQUENCE {
67 * algorithm AlgorithmIdentifier,
68 * subjectPublicKey BIT STRING
69 * }
70 *
71 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
72 *
73 * Extension ::= SEQUENCE {
74 * extnID OBJECT IDENTIFIER,
75 * critical BOOLEAN DEFAULT FALSE,
76 * extnValue OCTET STRING
77 * }
78 *
79 * The only key algorithm currently supported for PKI is RSA.
80 *
81 * RSASSA-PSS signatures are described in RFC 3447 and RFC 4055.
82 *
83 * PKCS#10 v1.7 describes certificate signing requests:
84 *
85 * CertificationRequestInfo:
86 *
87 * CertificationRequestInfo ::= SEQUENCE {
88 * version INTEGER { v1(0) } (v1,...),
89 * subject Name,
90 * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
91 * attributes [0] Attributes{{ CRIAttributes }}
92 * }
93 *
94 * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
95 *
96 * CRIAttributes ATTRIBUTE ::= {
97 * ... -- add any locally defined attributes here -- }
98 *
99 * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
100 * type ATTRIBUTE.&id({IOSet}),
101 * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})
102 * }
103 *
104 * CertificationRequest ::= SEQUENCE {
105 * certificationRequestInfo CertificationRequestInfo,
106 * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
107 * signature BIT STRING
108 * }
109 */
110var forge = require('./forge');
111require('./aes');
112require('./asn1');
113require('./des');
114require('./md');
115require('./mgf');
116require('./oids');
117require('./pem');
118require('./pss');
119require('./rsa');
120require('./util');
121
122// shortcut for asn.1 API
123var asn1 = forge.asn1;
124
125/* Public Key Infrastructure (PKI) implementation. */
126var pki = module.exports = forge.pki = forge.pki || {};
127var oids = pki.oids;
128
129// short name OID mappings
130var _shortNames = {};
131_shortNames['CN'] = oids['commonName'];
132_shortNames['commonName'] = 'CN';
133_shortNames['C'] = oids['countryName'];
134_shortNames['countryName'] = 'C';
135_shortNames['L'] = oids['localityName'];
136_shortNames['localityName'] = 'L';
137_shortNames['ST'] = oids['stateOrProvinceName'];
138_shortNames['stateOrProvinceName'] = 'ST';
139_shortNames['O'] = oids['organizationName'];
140_shortNames['organizationName'] = 'O';
141_shortNames['OU'] = oids['organizationalUnitName'];
142_shortNames['organizationalUnitName'] = 'OU';
143_shortNames['E'] = oids['emailAddress'];
144_shortNames['emailAddress'] = 'E';
145
146// validator for an SubjectPublicKeyInfo structure
147// Note: Currently only works with an RSA public key
148var publicKeyValidator = forge.pki.rsa.publicKeyValidator;
149
150// validator for an X.509v3 certificate
151var x509CertificateValidator = {
152 name: 'Certificate',
153 tagClass: asn1.Class.UNIVERSAL,
154 type: asn1.Type.SEQUENCE,
155 constructed: true,
156 value: [{
157 name: 'Certificate.TBSCertificate',
158 tagClass: asn1.Class.UNIVERSAL,
159 type: asn1.Type.SEQUENCE,
160 constructed: true,
161 captureAsn1: 'tbsCertificate',
162 value: [{
163 name: 'Certificate.TBSCertificate.version',
164 tagClass: asn1.Class.CONTEXT_SPECIFIC,
165 type: 0,
166 constructed: true,
167 optional: true,
168 value: [{
169 name: 'Certificate.TBSCertificate.version.integer',
170 tagClass: asn1.Class.UNIVERSAL,
171 type: asn1.Type.INTEGER,
172 constructed: false,
173 capture: 'certVersion'
174 }]
175 }, {
176 name: 'Certificate.TBSCertificate.serialNumber',
177 tagClass: asn1.Class.UNIVERSAL,
178 type: asn1.Type.INTEGER,
179 constructed: false,
180 capture: 'certSerialNumber'
181 }, {
182 name: 'Certificate.TBSCertificate.signature',
183 tagClass: asn1.Class.UNIVERSAL,
184 type: asn1.Type.SEQUENCE,
185 constructed: true,
186 value: [{
187 name: 'Certificate.TBSCertificate.signature.algorithm',
188 tagClass: asn1.Class.UNIVERSAL,
189 type: asn1.Type.OID,
190 constructed: false,
191 capture: 'certinfoSignatureOid'
192 }, {
193 name: 'Certificate.TBSCertificate.signature.parameters',
194 tagClass: asn1.Class.UNIVERSAL,
195 optional: true,
196 captureAsn1: 'certinfoSignatureParams'
197 }]
198 }, {
199 name: 'Certificate.TBSCertificate.issuer',
200 tagClass: asn1.Class.UNIVERSAL,
201 type: asn1.Type.SEQUENCE,
202 constructed: true,
203 captureAsn1: 'certIssuer'
204 }, {
205 name: 'Certificate.TBSCertificate.validity',
206 tagClass: asn1.Class.UNIVERSAL,
207 type: asn1.Type.SEQUENCE,
208 constructed: true,
209 // Note: UTC and generalized times may both appear so the capture
210 // names are based on their detected order, the names used below
211 // are only for the common case, which validity time really means
212 // "notBefore" and which means "notAfter" will be determined by order
213 value: [{
214 // notBefore (Time) (UTC time case)
215 name: 'Certificate.TBSCertificate.validity.notBefore (utc)',
216 tagClass: asn1.Class.UNIVERSAL,
217 type: asn1.Type.UTCTIME,
218 constructed: false,
219 optional: true,
220 capture: 'certValidity1UTCTime'
221 }, {
222 // notBefore (Time) (generalized time case)
223 name: 'Certificate.TBSCertificate.validity.notBefore (generalized)',
224 tagClass: asn1.Class.UNIVERSAL,
225 type: asn1.Type.GENERALIZEDTIME,
226 constructed: false,
227 optional: true,
228 capture: 'certValidity2GeneralizedTime'
229 }, {
230 // notAfter (Time) (only UTC time is supported)
231 name: 'Certificate.TBSCertificate.validity.notAfter (utc)',
232 tagClass: asn1.Class.UNIVERSAL,
233 type: asn1.Type.UTCTIME,
234 constructed: false,
235 optional: true,
236 capture: 'certValidity3UTCTime'
237 }, {
238 // notAfter (Time) (only UTC time is supported)
239 name: 'Certificate.TBSCertificate.validity.notAfter (generalized)',
240 tagClass: asn1.Class.UNIVERSAL,
241 type: asn1.Type.GENERALIZEDTIME,
242 constructed: false,
243 optional: true,
244 capture: 'certValidity4GeneralizedTime'
245 }]
246 }, {
247 // Name (subject) (RDNSequence)
248 name: 'Certificate.TBSCertificate.subject',
249 tagClass: asn1.Class.UNIVERSAL,
250 type: asn1.Type.SEQUENCE,
251 constructed: true,
252 captureAsn1: 'certSubject'
253 },
254 // SubjectPublicKeyInfo
255 publicKeyValidator,
256 {
257 // issuerUniqueID (optional)
258 name: 'Certificate.TBSCertificate.issuerUniqueID',
259 tagClass: asn1.Class.CONTEXT_SPECIFIC,
260 type: 1,
261 constructed: true,
262 optional: true,
263 value: [{
264 name: 'Certificate.TBSCertificate.issuerUniqueID.id',
265 tagClass: asn1.Class.UNIVERSAL,
266 type: asn1.Type.BITSTRING,
267 constructed: false,
268 // TODO: support arbitrary bit length ids
269 captureBitStringValue: 'certIssuerUniqueId'
270 }]
271 }, {
272 // subjectUniqueID (optional)
273 name: 'Certificate.TBSCertificate.subjectUniqueID',
274 tagClass: asn1.Class.CONTEXT_SPECIFIC,
275 type: 2,
276 constructed: true,
277 optional: true,
278 value: [{
279 name: 'Certificate.TBSCertificate.subjectUniqueID.id',
280 tagClass: asn1.Class.UNIVERSAL,
281 type: asn1.Type.BITSTRING,
282 constructed: false,
283 // TODO: support arbitrary bit length ids
284 captureBitStringValue: 'certSubjectUniqueId'
285 }]
286 }, {
287 // Extensions (optional)
288 name: 'Certificate.TBSCertificate.extensions',
289 tagClass: asn1.Class.CONTEXT_SPECIFIC,
290 type: 3,
291 constructed: true,
292 captureAsn1: 'certExtensions',
293 optional: true
294 }]
295 }, {
296 // AlgorithmIdentifier (signature algorithm)
297 name: 'Certificate.signatureAlgorithm',
298 tagClass: asn1.Class.UNIVERSAL,
299 type: asn1.Type.SEQUENCE,
300 constructed: true,
301 value: [{
302 // algorithm
303 name: 'Certificate.signatureAlgorithm.algorithm',
304 tagClass: asn1.Class.UNIVERSAL,
305 type: asn1.Type.OID,
306 constructed: false,
307 capture: 'certSignatureOid'
308 }, {
309 name: 'Certificate.TBSCertificate.signature.parameters',
310 tagClass: asn1.Class.UNIVERSAL,
311 optional: true,
312 captureAsn1: 'certSignatureParams'
313 }]
314 }, {
315 // SignatureValue
316 name: 'Certificate.signatureValue',
317 tagClass: asn1.Class.UNIVERSAL,
318 type: asn1.Type.BITSTRING,
319 constructed: false,
320 captureBitStringValue: 'certSignature'
321 }]
322};
323
324var rsassaPssParameterValidator = {
325 name: 'rsapss',
326 tagClass: asn1.Class.UNIVERSAL,
327 type: asn1.Type.SEQUENCE,
328 constructed: true,
329 value: [{
330 name: 'rsapss.hashAlgorithm',
331 tagClass: asn1.Class.CONTEXT_SPECIFIC,
332 type: 0,
333 constructed: true,
334 value: [{
335 name: 'rsapss.hashAlgorithm.AlgorithmIdentifier',
336 tagClass: asn1.Class.UNIVERSAL,
337 type: asn1.Class.SEQUENCE,
338 constructed: true,
339 optional: true,
340 value: [{
341 name: 'rsapss.hashAlgorithm.AlgorithmIdentifier.algorithm',
342 tagClass: asn1.Class.UNIVERSAL,
343 type: asn1.Type.OID,
344 constructed: false,
345 capture: 'hashOid'
346 /* parameter block omitted, for SHA1 NULL anyhow. */
347 }]
348 }]
349 }, {
350 name: 'rsapss.maskGenAlgorithm',
351 tagClass: asn1.Class.CONTEXT_SPECIFIC,
352 type: 1,
353 constructed: true,
354 value: [{
355 name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier',
356 tagClass: asn1.Class.UNIVERSAL,
357 type: asn1.Class.SEQUENCE,
358 constructed: true,
359 optional: true,
360 value: [{
361 name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.algorithm',
362 tagClass: asn1.Class.UNIVERSAL,
363 type: asn1.Type.OID,
364 constructed: false,
365 capture: 'maskGenOid'
366 }, {
367 name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params',
368 tagClass: asn1.Class.UNIVERSAL,
369 type: asn1.Type.SEQUENCE,
370 constructed: true,
371 value: [{
372 name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params.algorithm',
373 tagClass: asn1.Class.UNIVERSAL,
374 type: asn1.Type.OID,
375 constructed: false,
376 capture: 'maskGenHashOid'
377 /* parameter block omitted, for SHA1 NULL anyhow. */
378 }]
379 }]
380 }]
381 }, {
382 name: 'rsapss.saltLength',
383 tagClass: asn1.Class.CONTEXT_SPECIFIC,
384 type: 2,
385 optional: true,
386 value: [{
387 name: 'rsapss.saltLength.saltLength',
388 tagClass: asn1.Class.UNIVERSAL,
389 type: asn1.Class.INTEGER,
390 constructed: false,
391 capture: 'saltLength'
392 }]
393 }, {
394 name: 'rsapss.trailerField',
395 tagClass: asn1.Class.CONTEXT_SPECIFIC,
396 type: 3,
397 optional: true,
398 value: [{
399 name: 'rsapss.trailer.trailer',
400 tagClass: asn1.Class.UNIVERSAL,
401 type: asn1.Class.INTEGER,
402 constructed: false,
403 capture: 'trailer'
404 }]
405 }]
406};
407
408// validator for a CertificationRequestInfo structure
409var certificationRequestInfoValidator = {
410 name: 'CertificationRequestInfo',
411 tagClass: asn1.Class.UNIVERSAL,
412 type: asn1.Type.SEQUENCE,
413 constructed: true,
414 captureAsn1: 'certificationRequestInfo',
415 value: [{
416 name: 'CertificationRequestInfo.integer',
417 tagClass: asn1.Class.UNIVERSAL,
418 type: asn1.Type.INTEGER,
419 constructed: false,
420 capture: 'certificationRequestInfoVersion'
421 }, {
422 // Name (subject) (RDNSequence)
423 name: 'CertificationRequestInfo.subject',
424 tagClass: asn1.Class.UNIVERSAL,
425 type: asn1.Type.SEQUENCE,
426 constructed: true,
427 captureAsn1: 'certificationRequestInfoSubject'
428 },
429 // SubjectPublicKeyInfo
430 publicKeyValidator,
431 {
432 name: 'CertificationRequestInfo.attributes',
433 tagClass: asn1.Class.CONTEXT_SPECIFIC,
434 type: 0,
435 constructed: true,
436 optional: true,
437 capture: 'certificationRequestInfoAttributes',
438 value: [{
439 name: 'CertificationRequestInfo.attributes',
440 tagClass: asn1.Class.UNIVERSAL,
441 type: asn1.Type.SEQUENCE,
442 constructed: true,
443 value: [{
444 name: 'CertificationRequestInfo.attributes.type',
445 tagClass: asn1.Class.UNIVERSAL,
446 type: asn1.Type.OID,
447 constructed: false
448 }, {
449 name: 'CertificationRequestInfo.attributes.value',
450 tagClass: asn1.Class.UNIVERSAL,
451 type: asn1.Type.SET,
452 constructed: true
453 }]
454 }]
455 }]
456};
457
458// validator for a CertificationRequest structure
459var certificationRequestValidator = {
460 name: 'CertificationRequest',
461 tagClass: asn1.Class.UNIVERSAL,
462 type: asn1.Type.SEQUENCE,
463 constructed: true,
464 captureAsn1: 'csr',
465 value: [
466 certificationRequestInfoValidator, {
467 // AlgorithmIdentifier (signature algorithm)
468 name: 'CertificationRequest.signatureAlgorithm',
469 tagClass: asn1.Class.UNIVERSAL,
470 type: asn1.Type.SEQUENCE,
471 constructed: true,
472 value: [{
473 // algorithm
474 name: 'CertificationRequest.signatureAlgorithm.algorithm',
475 tagClass: asn1.Class.UNIVERSAL,
476 type: asn1.Type.OID,
477 constructed: false,
478 capture: 'csrSignatureOid'
479 }, {
480 name: 'CertificationRequest.signatureAlgorithm.parameters',
481 tagClass: asn1.Class.UNIVERSAL,
482 optional: true,
483 captureAsn1: 'csrSignatureParams'
484 }]
485 }, {
486 // signature
487 name: 'CertificationRequest.signature',
488 tagClass: asn1.Class.UNIVERSAL,
489 type: asn1.Type.BITSTRING,
490 constructed: false,
491 captureBitStringValue: 'csrSignature'
492 }
493 ]
494};
495
496/**
497 * Converts an RDNSequence of ASN.1 DER-encoded RelativeDistinguishedName
498 * sets into an array with objects that have type and value properties.
499 *
500 * @param rdn the RDNSequence to convert.
501 * @param md a message digest to append type and value to if provided.
502 */
503pki.RDNAttributesAsArray = function(rdn, md) {
504 var rval = [];
505
506 // each value in 'rdn' in is a SET of RelativeDistinguishedName
507 var set, attr, obj;
508 for(var si = 0; si < rdn.value.length; ++si) {
509 // get the RelativeDistinguishedName set
510 set = rdn.value[si];
511
512 // each value in the SET is an AttributeTypeAndValue sequence
513 // containing first a type (an OID) and second a value (defined by
514 // the OID)
515 for(var i = 0; i < set.value.length; ++i) {
516 obj = {};
517 attr = set.value[i];
518 obj.type = asn1.derToOid(attr.value[0].value);
519 obj.value = attr.value[1].value;
520 obj.valueTagClass = attr.value[1].type;
521 // if the OID is known, get its name and short name
522 if(obj.type in oids) {
523 obj.name = oids[obj.type];
524 if(obj.name in _shortNames) {
525 obj.shortName = _shortNames[obj.name];
526 }
527 }
528 if(md) {
529 md.update(obj.type);
530 md.update(obj.value);
531 }
532 rval.push(obj);
533 }
534 }
535
536 return rval;
537};
538
539/**
540 * Converts ASN.1 CRIAttributes into an array with objects that have type and
541 * value properties.
542 *
543 * @param attributes the CRIAttributes to convert.
544 */
545pki.CRIAttributesAsArray = function(attributes) {
546 var rval = [];
547
548 // each value in 'attributes' in is a SEQUENCE with an OID and a SET
549 for(var si = 0; si < attributes.length; ++si) {
550 // get the attribute sequence
551 var seq = attributes[si];
552
553 // each value in the SEQUENCE containing first a type (an OID) and
554 // second a set of values (defined by the OID)
555 var type = asn1.derToOid(seq.value[0].value);
556 var values = seq.value[1].value;
557 for(var vi = 0; vi < values.length; ++vi) {
558 var obj = {};
559 obj.type = type;
560 obj.value = values[vi].value;
561 obj.valueTagClass = values[vi].type;
562 // if the OID is known, get its name and short name
563 if(obj.type in oids) {
564 obj.name = oids[obj.type];
565 if(obj.name in _shortNames) {
566 obj.shortName = _shortNames[obj.name];
567 }
568 }
569 // parse extensions
570 if(obj.type === oids.extensionRequest) {
571 obj.extensions = [];
572 for(var ei = 0; ei < obj.value.length; ++ei) {
573 obj.extensions.push(pki.certificateExtensionFromAsn1(obj.value[ei]));
574 }
575 }
576 rval.push(obj);
577 }
578 }
579
580 return rval;
581};
582
583/**
584 * Gets an issuer or subject attribute from its name, type, or short name.
585 *
586 * @param obj the issuer or subject object.
587 * @param options a short name string or an object with:
588 * shortName the short name for the attribute.
589 * name the name for the attribute.
590 * type the type for the attribute.
591 *
592 * @return the attribute.
593 */
594function _getAttribute(obj, options) {
595 if(typeof options === 'string') {
596 options = {shortName: options};
597 }
598
599 var rval = null;
600 var attr;
601 for(var i = 0; rval === null && i < obj.attributes.length; ++i) {
602 attr = obj.attributes[i];
603 if(options.type && options.type === attr.type) {
604 rval = attr;
605 } else if(options.name && options.name === attr.name) {
606 rval = attr;
607 } else if(options.shortName && options.shortName === attr.shortName) {
608 rval = attr;
609 }
610 }
611 return rval;
612}
613
614/**
615 * Converts signature parameters from ASN.1 structure.
616 *
617 * Currently only RSASSA-PSS supported. The PKCS#1 v1.5 signature scheme had
618 * no parameters.
619 *
620 * RSASSA-PSS-params ::= SEQUENCE {
621 * hashAlgorithm [0] HashAlgorithm DEFAULT
622 * sha1Identifier,
623 * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT
624 * mgf1SHA1Identifier,
625 * saltLength [2] INTEGER DEFAULT 20,
626 * trailerField [3] INTEGER DEFAULT 1
627 * }
628 *
629 * HashAlgorithm ::= AlgorithmIdentifier
630 *
631 * MaskGenAlgorithm ::= AlgorithmIdentifier
632 *
633 * AlgorithmIdentifer ::= SEQUENCE {
634 * algorithm OBJECT IDENTIFIER,
635 * parameters ANY DEFINED BY algorithm OPTIONAL
636 * }
637 *
638 * @param oid The OID specifying the signature algorithm
639 * @param obj The ASN.1 structure holding the parameters
640 * @param fillDefaults Whether to use return default values where omitted
641 * @return signature parameter object
642 */
643var _readSignatureParameters = function(oid, obj, fillDefaults) {
644 var params = {};
645
646 if(oid !== oids['RSASSA-PSS']) {
647 return params;
648 }
649
650 if(fillDefaults) {
651 params = {
652 hash: {
653 algorithmOid: oids['sha1']
654 },
655 mgf: {
656 algorithmOid: oids['mgf1'],
657 hash: {
658 algorithmOid: oids['sha1']
659 }
660 },
661 saltLength: 20
662 };
663 }
664
665 var capture = {};
666 var errors = [];
667 if(!asn1.validate(obj, rsassaPssParameterValidator, capture, errors)) {
668 var error = new Error('Cannot read RSASSA-PSS parameter block.');
669 error.errors = errors;
670 throw error;
671 }
672
673 if(capture.hashOid !== undefined) {
674 params.hash = params.hash || {};
675 params.hash.algorithmOid = asn1.derToOid(capture.hashOid);
676 }
677
678 if(capture.maskGenOid !== undefined) {
679 params.mgf = params.mgf || {};
680 params.mgf.algorithmOid = asn1.derToOid(capture.maskGenOid);
681 params.mgf.hash = params.mgf.hash || {};
682 params.mgf.hash.algorithmOid = asn1.derToOid(capture.maskGenHashOid);
683 }
684
685 if(capture.saltLength !== undefined) {
686 params.saltLength = capture.saltLength.charCodeAt(0);
687 }
688
689 return params;
690};
691
692/**
693 * Create signature digest for OID.
694 *
695 * @param options
696 * signatureOid: the OID specifying the signature algorithm.
697 * type: a human readable type for error messages
698 * @return a created md instance. throws if unknown oid.
699 */
700var _createSignatureDigest = function(options) {
701 switch(oids[options.signatureOid]) {
702 case 'sha1WithRSAEncryption':
703 // deprecated alias
704 case 'sha1WithRSASignature':
705 return forge.md.sha1.create();
706 case 'md5WithRSAEncryption':
707 return forge.md.md5.create();
708 case 'sha256WithRSAEncryption':
709 return forge.md.sha256.create();
710 case 'sha384WithRSAEncryption':
711 return forge.md.sha384.create();
712 case 'sha512WithRSAEncryption':
713 return forge.md.sha512.create();
714 case 'RSASSA-PSS':
715 return forge.md.sha256.create();
716 default:
717 var error = new Error(
718 'Could not compute ' + options.type + ' digest. ' +
719 'Unknown signature OID.');
720 error.signatureOid = options.signatureOid;
721 throw error;
722 }
723};
724
725/**
726 * Verify signature on certificate or CSR.
727 *
728 * @param options:
729 * certificate the certificate or CSR to verify.
730 * md the signature digest.
731 * signature the signature
732 * @return a created md instance. throws if unknown oid.
733 */
734var _verifySignature = function(options) {
735 var cert = options.certificate;
736 var scheme;
737
738 switch(cert.signatureOid) {
739 case oids.sha1WithRSAEncryption:
740 // deprecated alias
741 case oids.sha1WithRSASignature:
742 /* use PKCS#1 v1.5 padding scheme */
743 break;
744 case oids['RSASSA-PSS']:
745 var hash, mgf;
746
747 /* initialize mgf */
748 hash = oids[cert.signatureParameters.mgf.hash.algorithmOid];
749 if(hash === undefined || forge.md[hash] === undefined) {
750 var error = new Error('Unsupported MGF hash function.');
751 error.oid = cert.signatureParameters.mgf.hash.algorithmOid;
752 error.name = hash;
753 throw error;
754 }
755
756 mgf = oids[cert.signatureParameters.mgf.algorithmOid];
757 if(mgf === undefined || forge.mgf[mgf] === undefined) {
758 var error = new Error('Unsupported MGF function.');
759 error.oid = cert.signatureParameters.mgf.algorithmOid;
760 error.name = mgf;
761 throw error;
762 }
763
764 mgf = forge.mgf[mgf].create(forge.md[hash].create());
765
766 /* initialize hash function */
767 hash = oids[cert.signatureParameters.hash.algorithmOid];
768 if(hash === undefined || forge.md[hash] === undefined) {
769 var error = new Error('Unsupported RSASSA-PSS hash function.');
770 error.oid = cert.signatureParameters.hash.algorithmOid;
771 error.name = hash;
772 throw error;
773 }
774
775 scheme = forge.pss.create(
776 forge.md[hash].create(), mgf, cert.signatureParameters.saltLength
777 );
778 break;
779 }
780
781 // verify signature on cert using public key
782 return cert.publicKey.verify(
783 options.md.digest().getBytes(), options.signature, scheme
784 );
785};
786
787/**
788 * Converts an X.509 certificate from PEM format.
789 *
790 * Note: If the certificate is to be verified then compute hash should
791 * be set to true. This will scan the TBSCertificate part of the ASN.1
792 * object while it is converted so it doesn't need to be converted back
793 * to ASN.1-DER-encoding later.
794 *
795 * @param pem the PEM-formatted certificate.
796 * @param computeHash true to compute the hash for verification.
797 * @param strict true to be strict when checking ASN.1 value lengths, false to
798 * allow truncated values (default: true).
799 *
800 * @return the certificate.
801 */
802pki.certificateFromPem = function(pem, computeHash, strict) {
803 var msg = forge.pem.decode(pem)[0];
804
805 if(msg.type !== 'CERTIFICATE' &&
806 msg.type !== 'X509 CERTIFICATE' &&
807 msg.type !== 'TRUSTED CERTIFICATE') {
808 var error = new Error(
809 'Could not convert certificate from PEM; PEM header type ' +
810 'is not "CERTIFICATE", "X509 CERTIFICATE", or "TRUSTED CERTIFICATE".');
811 error.headerType = msg.type;
812 throw error;
813 }
814 if(msg.procType && msg.procType.type === 'ENCRYPTED') {
815 throw new Error(
816 'Could not convert certificate from PEM; PEM is encrypted.');
817 }
818
819 // convert DER to ASN.1 object
820 var obj = asn1.fromDer(msg.body, strict);
821
822 return pki.certificateFromAsn1(obj, computeHash);
823};
824
825/**
826 * Converts an X.509 certificate to PEM format.
827 *
828 * @param cert the certificate.
829 * @param maxline the maximum characters per line, defaults to 64.
830 *
831 * @return the PEM-formatted certificate.
832 */
833pki.certificateToPem = function(cert, maxline) {
834 // convert to ASN.1, then DER, then PEM-encode
835 var msg = {
836 type: 'CERTIFICATE',
837 body: asn1.toDer(pki.certificateToAsn1(cert)).getBytes()
838 };
839 return forge.pem.encode(msg, {maxline: maxline});
840};
841
842/**
843 * Converts an RSA public key from PEM format.
844 *
845 * @param pem the PEM-formatted public key.
846 *
847 * @return the public key.
848 */
849pki.publicKeyFromPem = function(pem) {
850 var msg = forge.pem.decode(pem)[0];
851
852 if(msg.type !== 'PUBLIC KEY' && msg.type !== 'RSA PUBLIC KEY') {
853 var error = new Error('Could not convert public key from PEM; PEM header ' +
854 'type is not "PUBLIC KEY" or "RSA PUBLIC KEY".');
855 error.headerType = msg.type;
856 throw error;
857 }
858 if(msg.procType && msg.procType.type === 'ENCRYPTED') {
859 throw new Error('Could not convert public key from PEM; PEM is encrypted.');
860 }
861
862 // convert DER to ASN.1 object
863 var obj = asn1.fromDer(msg.body);
864
865 return pki.publicKeyFromAsn1(obj);
866};
867
868/**
869 * Converts an RSA public key to PEM format (using a SubjectPublicKeyInfo).
870 *
871 * @param key the public key.
872 * @param maxline the maximum characters per line, defaults to 64.
873 *
874 * @return the PEM-formatted public key.
875 */
876pki.publicKeyToPem = function(key, maxline) {
877 // convert to ASN.1, then DER, then PEM-encode
878 var msg = {
879 type: 'PUBLIC KEY',
880 body: asn1.toDer(pki.publicKeyToAsn1(key)).getBytes()
881 };
882 return forge.pem.encode(msg, {maxline: maxline});
883};
884
885/**
886 * Converts an RSA public key to PEM format (using an RSAPublicKey).
887 *
888 * @param key the public key.
889 * @param maxline the maximum characters per line, defaults to 64.
890 *
891 * @return the PEM-formatted public key.
892 */
893pki.publicKeyToRSAPublicKeyPem = function(key, maxline) {
894 // convert to ASN.1, then DER, then PEM-encode
895 var msg = {
896 type: 'RSA PUBLIC KEY',
897 body: asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes()
898 };
899 return forge.pem.encode(msg, {maxline: maxline});
900};
901
902/**
903 * Gets a fingerprint for the given public key.
904 *
905 * @param options the options to use.
906 * [md] the message digest object to use (defaults to forge.md.sha1).
907 * [type] the type of fingerprint, such as 'RSAPublicKey',
908 * 'SubjectPublicKeyInfo' (defaults to 'RSAPublicKey').
909 * [encoding] an alternative output encoding, such as 'hex'
910 * (defaults to none, outputs a byte buffer).
911 * [delimiter] the delimiter to use between bytes for 'hex' encoded
912 * output, eg: ':' (defaults to none).
913 *
914 * @return the fingerprint as a byte buffer or other encoding based on options.
915 */
916pki.getPublicKeyFingerprint = function(key, options) {
917 options = options || {};
918 var md = options.md || forge.md.sha1.create();
919 var type = options.type || 'RSAPublicKey';
920
921 var bytes;
922 switch(type) {
923 case 'RSAPublicKey':
924 bytes = asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes();
925 break;
926 case 'SubjectPublicKeyInfo':
927 bytes = asn1.toDer(pki.publicKeyToAsn1(key)).getBytes();
928 break;
929 default:
930 throw new Error('Unknown fingerprint type "' + options.type + '".');
931 }
932
933 // hash public key bytes
934 md.start();
935 md.update(bytes);
936 var digest = md.digest();
937 if(options.encoding === 'hex') {
938 var hex = digest.toHex();
939 if(options.delimiter) {
940 return hex.match(/.{2}/g).join(options.delimiter);
941 }
942 return hex;
943 } else if(options.encoding === 'binary') {
944 return digest.getBytes();
945 } else if(options.encoding) {
946 throw new Error('Unknown encoding "' + options.encoding + '".');
947 }
948 return digest;
949};
950
951/**
952 * Converts a PKCS#10 certification request (CSR) from PEM format.
953 *
954 * Note: If the certification request is to be verified then compute hash
955 * should be set to true. This will scan the CertificationRequestInfo part of
956 * the ASN.1 object while it is converted so it doesn't need to be converted
957 * back to ASN.1-DER-encoding later.
958 *
959 * @param pem the PEM-formatted certificate.
960 * @param computeHash true to compute the hash for verification.
961 * @param strict true to be strict when checking ASN.1 value lengths, false to
962 * allow truncated values (default: true).
963 *
964 * @return the certification request (CSR).
965 */
966pki.certificationRequestFromPem = function(pem, computeHash, strict) {
967 var msg = forge.pem.decode(pem)[0];
968
969 if(msg.type !== 'CERTIFICATE REQUEST') {
970 var error = new Error('Could not convert certification request from PEM; ' +
971 'PEM header type is not "CERTIFICATE REQUEST".');
972 error.headerType = msg.type;
973 throw error;
974 }
975 if(msg.procType && msg.procType.type === 'ENCRYPTED') {
976 throw new Error('Could not convert certification request from PEM; ' +
977 'PEM is encrypted.');
978 }
979
980 // convert DER to ASN.1 object
981 var obj = asn1.fromDer(msg.body, strict);
982
983 return pki.certificationRequestFromAsn1(obj, computeHash);
984};
985
986/**
987 * Converts a PKCS#10 certification request (CSR) to PEM format.
988 *
989 * @param csr the certification request.
990 * @param maxline the maximum characters per line, defaults to 64.
991 *
992 * @return the PEM-formatted certification request.
993 */
994pki.certificationRequestToPem = function(csr, maxline) {
995 // convert to ASN.1, then DER, then PEM-encode
996 var msg = {
997 type: 'CERTIFICATE REQUEST',
998 body: asn1.toDer(pki.certificationRequestToAsn1(csr)).getBytes()
999 };
1000 return forge.pem.encode(msg, {maxline: maxline});
1001};
1002
1003/**
1004 * Creates an empty X.509v3 RSA certificate.
1005 *
1006 * @return the certificate.
1007 */
1008pki.createCertificate = function() {
1009 var cert = {};
1010 cert.version = 0x02;
1011 cert.serialNumber = '00';
1012 cert.signatureOid = null;
1013 cert.signature = null;
1014 cert.siginfo = {};
1015 cert.siginfo.algorithmOid = null;
1016 cert.validity = {};
1017 cert.validity.notBefore = new Date();
1018 cert.validity.notAfter = new Date();
1019
1020 cert.issuer = {};
1021 cert.issuer.getField = function(sn) {
1022 return _getAttribute(cert.issuer, sn);
1023 };
1024 cert.issuer.addField = function(attr) {
1025 _fillMissingFields([attr]);
1026 cert.issuer.attributes.push(attr);
1027 };
1028 cert.issuer.attributes = [];
1029 cert.issuer.hash = null;
1030
1031 cert.subject = {};
1032 cert.subject.getField = function(sn) {
1033 return _getAttribute(cert.subject, sn);
1034 };
1035 cert.subject.addField = function(attr) {
1036 _fillMissingFields([attr]);
1037 cert.subject.attributes.push(attr);
1038 };
1039 cert.subject.attributes = [];
1040 cert.subject.hash = null;
1041
1042 cert.extensions = [];
1043 cert.publicKey = null;
1044 cert.md = null;
1045
1046 /**
1047 * Sets the subject of this certificate.
1048 *
1049 * @param attrs the array of subject attributes to use.
1050 * @param uniqueId an optional a unique ID to use.
1051 */
1052 cert.setSubject = function(attrs, uniqueId) {
1053 // set new attributes, clear hash
1054 _fillMissingFields(attrs);
1055 cert.subject.attributes = attrs;
1056 delete cert.subject.uniqueId;
1057 if(uniqueId) {
1058 // TODO: support arbitrary bit length ids
1059 cert.subject.uniqueId = uniqueId;
1060 }
1061 cert.subject.hash = null;
1062 };
1063
1064 /**
1065 * Sets the issuer of this certificate.
1066 *
1067 * @param attrs the array of issuer attributes to use.
1068 * @param uniqueId an optional a unique ID to use.
1069 */
1070 cert.setIssuer = function(attrs, uniqueId) {
1071 // set new attributes, clear hash
1072 _fillMissingFields(attrs);
1073 cert.issuer.attributes = attrs;
1074 delete cert.issuer.uniqueId;
1075 if(uniqueId) {
1076 // TODO: support arbitrary bit length ids
1077 cert.issuer.uniqueId = uniqueId;
1078 }
1079 cert.issuer.hash = null;
1080 };
1081
1082 /**
1083 * Sets the extensions of this certificate.
1084 *
1085 * @param exts the array of extensions to use.
1086 */
1087 cert.setExtensions = function(exts) {
1088 for(var i = 0; i < exts.length; ++i) {
1089 _fillMissingExtensionFields(exts[i], {cert: cert});
1090 }
1091 // set new extensions
1092 cert.extensions = exts;
1093 };
1094
1095 /**
1096 * Gets an extension by its name or id.
1097 *
1098 * @param options the name to use or an object with:
1099 * name the name to use.
1100 * id the id to use.
1101 *
1102 * @return the extension or null if not found.
1103 */
1104 cert.getExtension = function(options) {
1105 if(typeof options === 'string') {
1106 options = {name: options};
1107 }
1108
1109 var rval = null;
1110 var ext;
1111 for(var i = 0; rval === null && i < cert.extensions.length; ++i) {
1112 ext = cert.extensions[i];
1113 if(options.id && ext.id === options.id) {
1114 rval = ext;
1115 } else if(options.name && ext.name === options.name) {
1116 rval = ext;
1117 }
1118 }
1119 return rval;
1120 };
1121
1122 /**
1123 * Signs this certificate using the given private key.
1124 *
1125 * @param key the private key to sign with.
1126 * @param md the message digest object to use (defaults to forge.md.sha1).
1127 */
1128 cert.sign = function(key, md) {
1129 // TODO: get signature OID from private key
1130 cert.md = md || forge.md.sha1.create();
1131 var algorithmOid = oids[cert.md.algorithm + 'WithRSAEncryption'];
1132 if(!algorithmOid) {
1133 var error = new Error('Could not compute certificate digest. ' +
1134 'Unknown message digest algorithm OID.');
1135 error.algorithm = cert.md.algorithm;
1136 throw error;
1137 }
1138 cert.signatureOid = cert.siginfo.algorithmOid = algorithmOid;
1139
1140 // get TBSCertificate, convert to DER
1141 cert.tbsCertificate = pki.getTBSCertificate(cert);
1142 var bytes = asn1.toDer(cert.tbsCertificate);
1143
1144 // digest and sign
1145 cert.md.update(bytes.getBytes());
1146 cert.signature = key.sign(cert.md);
1147 };
1148
1149 /**
1150 * Attempts verify the signature on the passed certificate using this
1151 * certificate's public key.
1152 *
1153 * @param child the certificate to verify.
1154 *
1155 * @return true if verified, false if not.
1156 */
1157 cert.verify = function(child) {
1158 var rval = false;
1159
1160 if(!cert.issued(child)) {
1161 var issuer = child.issuer;
1162 var subject = cert.subject;
1163 var error = new Error(
1164 'The parent certificate did not issue the given child ' +
1165 'certificate; the child certificate\'s issuer does not match the ' +
1166 'parent\'s subject.');
1167 error.expectedIssuer = subject.attributes;
1168 error.actualIssuer = issuer.attributes;
1169 throw error;
1170 }
1171
1172 var md = child.md;
1173 if(md === null) {
1174 // create digest for OID signature types
1175 md = _createSignatureDigest({
1176 signatureOid: child.signatureOid,
1177 type: 'certificate'
1178 });
1179
1180 // produce DER formatted TBSCertificate and digest it
1181 var tbsCertificate = child.tbsCertificate || pki.getTBSCertificate(child);
1182 var bytes = asn1.toDer(tbsCertificate);
1183 md.update(bytes.getBytes());
1184 }
1185
1186 if(md !== null) {
1187 rval = _verifySignature({
1188 certificate: cert, md: md, signature: child.signature
1189 });
1190 }
1191
1192 return rval;
1193 };
1194
1195 /**
1196 * Returns true if this certificate's issuer matches the passed
1197 * certificate's subject. Note that no signature check is performed.
1198 *
1199 * @param parent the certificate to check.
1200 *
1201 * @return true if this certificate's issuer matches the passed certificate's
1202 * subject.
1203 */
1204 cert.isIssuer = function(parent) {
1205 var rval = false;
1206
1207 var i = cert.issuer;
1208 var s = parent.subject;
1209
1210 // compare hashes if present
1211 if(i.hash && s.hash) {
1212 rval = (i.hash === s.hash);
1213 } else if(i.attributes.length === s.attributes.length) {
1214 // all attributes are the same so issuer matches subject
1215 rval = true;
1216 var iattr, sattr;
1217 for(var n = 0; rval && n < i.attributes.length; ++n) {
1218 iattr = i.attributes[n];
1219 sattr = s.attributes[n];
1220 if(iattr.type !== sattr.type || iattr.value !== sattr.value) {
1221 // attribute mismatch
1222 rval = false;
1223 }
1224 }
1225 }
1226
1227 return rval;
1228 };
1229
1230 /**
1231 * Returns true if this certificate's subject matches the issuer of the
1232 * given certificate). Note that not signature check is performed.
1233 *
1234 * @param child the certificate to check.
1235 *
1236 * @return true if this certificate's subject matches the passed
1237 * certificate's issuer.
1238 */
1239 cert.issued = function(child) {
1240 return child.isIssuer(cert);
1241 };
1242
1243 /**
1244 * Generates the subjectKeyIdentifier for this certificate as byte buffer.
1245 *
1246 * @return the subjectKeyIdentifier for this certificate as byte buffer.
1247 */
1248 cert.generateSubjectKeyIdentifier = function() {
1249 /* See: 4.2.1.2 section of the the RFC3280, keyIdentifier is either:
1250
1251 (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
1252 value of the BIT STRING subjectPublicKey (excluding the tag,
1253 length, and number of unused bits).
1254
1255 (2) The keyIdentifier is composed of a four bit type field with
1256 the value 0100 followed by the least significant 60 bits of the
1257 SHA-1 hash of the value of the BIT STRING subjectPublicKey
1258 (excluding the tag, length, and number of unused bit string bits).
1259 */
1260
1261 // skipping the tag, length, and number of unused bits is the same
1262 // as just using the RSAPublicKey (for RSA keys, which are the
1263 // only ones supported)
1264 return pki.getPublicKeyFingerprint(cert.publicKey, {type: 'RSAPublicKey'});
1265 };
1266
1267 /**
1268 * Verifies the subjectKeyIdentifier extension value for this certificate
1269 * against its public key. If no extension is found, false will be
1270 * returned.
1271 *
1272 * @return true if verified, false if not.
1273 */
1274 cert.verifySubjectKeyIdentifier = function() {
1275 var oid = oids['subjectKeyIdentifier'];
1276 for(var i = 0; i < cert.extensions.length; ++i) {
1277 var ext = cert.extensions[i];
1278 if(ext.id === oid) {
1279 var ski = cert.generateSubjectKeyIdentifier().getBytes();
1280 return (forge.util.hexToBytes(ext.subjectKeyIdentifier) === ski);
1281 }
1282 }
1283 return false;
1284 };
1285
1286 return cert;
1287};
1288
1289/**
1290 * Converts an X.509v3 RSA certificate from an ASN.1 object.
1291 *
1292 * Note: If the certificate is to be verified then compute hash should
1293 * be set to true. There is currently no implementation for converting
1294 * a certificate back to ASN.1 so the TBSCertificate part of the ASN.1
1295 * object needs to be scanned before the cert object is created.
1296 *
1297 * @param obj the asn1 representation of an X.509v3 RSA certificate.
1298 * @param computeHash true to compute the hash for verification.
1299 *
1300 * @return the certificate.
1301 */
1302pki.certificateFromAsn1 = function(obj, computeHash) {
1303 // validate certificate and capture data
1304 var capture = {};
1305 var errors = [];
1306 if(!asn1.validate(obj, x509CertificateValidator, capture, errors)) {
1307 var error = new Error('Cannot read X.509 certificate. ' +
1308 'ASN.1 object is not an X509v3 Certificate.');
1309 error.errors = errors;
1310 throw error;
1311 }
1312
1313 // get oid
1314 var oid = asn1.derToOid(capture.publicKeyOid);
1315 if(oid !== pki.oids.rsaEncryption) {
1316 throw new Error('Cannot read public key. OID is not RSA.');
1317 }
1318
1319 // create certificate
1320 var cert = pki.createCertificate();
1321 cert.version = capture.certVersion ?
1322 capture.certVersion.charCodeAt(0) : 0;
1323 var serial = forge.util.createBuffer(capture.certSerialNumber);
1324 cert.serialNumber = serial.toHex();
1325 cert.signatureOid = forge.asn1.derToOid(capture.certSignatureOid);
1326 cert.signatureParameters = _readSignatureParameters(
1327 cert.signatureOid, capture.certSignatureParams, true);
1328 cert.siginfo.algorithmOid = forge.asn1.derToOid(capture.certinfoSignatureOid);
1329 cert.siginfo.parameters = _readSignatureParameters(cert.siginfo.algorithmOid,
1330 capture.certinfoSignatureParams, false);
1331 cert.signature = capture.certSignature;
1332
1333 var validity = [];
1334 if(capture.certValidity1UTCTime !== undefined) {
1335 validity.push(asn1.utcTimeToDate(capture.certValidity1UTCTime));
1336 }
1337 if(capture.certValidity2GeneralizedTime !== undefined) {
1338 validity.push(asn1.generalizedTimeToDate(
1339 capture.certValidity2GeneralizedTime));
1340 }
1341 if(capture.certValidity3UTCTime !== undefined) {
1342 validity.push(asn1.utcTimeToDate(capture.certValidity3UTCTime));
1343 }
1344 if(capture.certValidity4GeneralizedTime !== undefined) {
1345 validity.push(asn1.generalizedTimeToDate(
1346 capture.certValidity4GeneralizedTime));
1347 }
1348 if(validity.length > 2) {
1349 throw new Error('Cannot read notBefore/notAfter validity times; more ' +
1350 'than two times were provided in the certificate.');
1351 }
1352 if(validity.length < 2) {
1353 throw new Error('Cannot read notBefore/notAfter validity times; they ' +
1354 'were not provided as either UTCTime or GeneralizedTime.');
1355 }
1356 cert.validity.notBefore = validity[0];
1357 cert.validity.notAfter = validity[1];
1358
1359 // keep TBSCertificate to preserve signature when exporting
1360 cert.tbsCertificate = capture.tbsCertificate;
1361
1362 if(computeHash) {
1363 // create digest for OID signature type
1364 cert.md = _createSignatureDigest({
1365 signatureOid: cert.signatureOid,
1366 type: 'certificate'
1367 });
1368
1369 // produce DER formatted TBSCertificate and digest it
1370 var bytes = asn1.toDer(cert.tbsCertificate);
1371 cert.md.update(bytes.getBytes());
1372 }
1373
1374 // handle issuer, build issuer message digest
1375 var imd = forge.md.sha1.create();
1376 var ibytes = asn1.toDer(capture.certIssuer);
1377 imd.update(ibytes.getBytes());
1378 cert.issuer.getField = function(sn) {
1379 return _getAttribute(cert.issuer, sn);
1380 };
1381 cert.issuer.addField = function(attr) {
1382 _fillMissingFields([attr]);
1383 cert.issuer.attributes.push(attr);
1384 };
1385 cert.issuer.attributes = pki.RDNAttributesAsArray(capture.certIssuer);
1386 if(capture.certIssuerUniqueId) {
1387 cert.issuer.uniqueId = capture.certIssuerUniqueId;
1388 }
1389 cert.issuer.hash = imd.digest().toHex();
1390
1391 // handle subject, build subject message digest
1392 var smd = forge.md.sha1.create();
1393 var sbytes = asn1.toDer(capture.certSubject);
1394 smd.update(sbytes.getBytes());
1395 cert.subject.getField = function(sn) {
1396 return _getAttribute(cert.subject, sn);
1397 };
1398 cert.subject.addField = function(attr) {
1399 _fillMissingFields([attr]);
1400 cert.subject.attributes.push(attr);
1401 };
1402 cert.subject.attributes = pki.RDNAttributesAsArray(capture.certSubject);
1403 if(capture.certSubjectUniqueId) {
1404 cert.subject.uniqueId = capture.certSubjectUniqueId;
1405 }
1406 cert.subject.hash = smd.digest().toHex();
1407
1408 // handle extensions
1409 if(capture.certExtensions) {
1410 cert.extensions = pki.certificateExtensionsFromAsn1(capture.certExtensions);
1411 } else {
1412 cert.extensions = [];
1413 }
1414
1415 // convert RSA public key from ASN.1
1416 cert.publicKey = pki.publicKeyFromAsn1(capture.subjectPublicKeyInfo);
1417
1418 return cert;
1419};
1420
1421/**
1422 * Converts an ASN.1 extensions object (with extension sequences as its
1423 * values) into an array of extension objects with types and values.
1424 *
1425 * Supported extensions:
1426 *
1427 * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
1428 * KeyUsage ::= BIT STRING {
1429 * digitalSignature (0),
1430 * nonRepudiation (1),
1431 * keyEncipherment (2),
1432 * dataEncipherment (3),
1433 * keyAgreement (4),
1434 * keyCertSign (5),
1435 * cRLSign (6),
1436 * encipherOnly (7),
1437 * decipherOnly (8)
1438 * }
1439 *
1440 * id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 }
1441 * BasicConstraints ::= SEQUENCE {
1442 * cA BOOLEAN DEFAULT FALSE,
1443 * pathLenConstraint INTEGER (0..MAX) OPTIONAL
1444 * }
1445 *
1446 * subjectAltName EXTENSION ::= {
1447 * SYNTAX GeneralNames
1448 * IDENTIFIED BY id-ce-subjectAltName
1449 * }
1450 *
1451 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
1452 *
1453 * GeneralName ::= CHOICE {
1454 * otherName [0] INSTANCE OF OTHER-NAME,
1455 * rfc822Name [1] IA5String,
1456 * dNSName [2] IA5String,
1457 * x400Address [3] ORAddress,
1458 * directoryName [4] Name,
1459 * ediPartyName [5] EDIPartyName,
1460 * uniformResourceIdentifier [6] IA5String,
1461 * IPAddress [7] OCTET STRING,
1462 * registeredID [8] OBJECT IDENTIFIER
1463 * }
1464 *
1465 * OTHER-NAME ::= TYPE-IDENTIFIER
1466 *
1467 * EDIPartyName ::= SEQUENCE {
1468 * nameAssigner [0] DirectoryString {ub-name} OPTIONAL,
1469 * partyName [1] DirectoryString {ub-name}
1470 * }
1471 *
1472 * @param exts the extensions ASN.1 with extension sequences to parse.
1473 *
1474 * @return the array.
1475 */
1476pki.certificateExtensionsFromAsn1 = function(exts) {
1477 var rval = [];
1478 for(var i = 0; i < exts.value.length; ++i) {
1479 // get extension sequence
1480 var extseq = exts.value[i];
1481 for(var ei = 0; ei < extseq.value.length; ++ei) {
1482 rval.push(pki.certificateExtensionFromAsn1(extseq.value[ei]));
1483 }
1484 }
1485
1486 return rval;
1487};
1488
1489/**
1490 * Parses a single certificate extension from ASN.1.
1491 *
1492 * @param ext the extension in ASN.1 format.
1493 *
1494 * @return the parsed extension as an object.
1495 */
1496pki.certificateExtensionFromAsn1 = function(ext) {
1497 // an extension has:
1498 // [0] extnID OBJECT IDENTIFIER
1499 // [1] critical BOOLEAN DEFAULT FALSE
1500 // [2] extnValue OCTET STRING
1501 var e = {};
1502 e.id = asn1.derToOid(ext.value[0].value);
1503 e.critical = false;
1504 if(ext.value[1].type === asn1.Type.BOOLEAN) {
1505 e.critical = (ext.value[1].value.charCodeAt(0) !== 0x00);
1506 e.value = ext.value[2].value;
1507 } else {
1508 e.value = ext.value[1].value;
1509 }
1510 // if the oid is known, get its name
1511 if(e.id in oids) {
1512 e.name = oids[e.id];
1513
1514 // handle key usage
1515 if(e.name === 'keyUsage') {
1516 // get value as BIT STRING
1517 var ev = asn1.fromDer(e.value);
1518 var b2 = 0x00;
1519 var b3 = 0x00;
1520 if(ev.value.length > 1) {
1521 // skip first byte, just indicates unused bits which
1522 // will be padded with 0s anyway
1523 // get bytes with flag bits
1524 b2 = ev.value.charCodeAt(1);
1525 b3 = ev.value.length > 2 ? ev.value.charCodeAt(2) : 0;
1526 }
1527 // set flags
1528 e.digitalSignature = (b2 & 0x80) === 0x80;
1529 e.nonRepudiation = (b2 & 0x40) === 0x40;
1530 e.keyEncipherment = (b2 & 0x20) === 0x20;
1531 e.dataEncipherment = (b2 & 0x10) === 0x10;
1532 e.keyAgreement = (b2 & 0x08) === 0x08;
1533 e.keyCertSign = (b2 & 0x04) === 0x04;
1534 e.cRLSign = (b2 & 0x02) === 0x02;
1535 e.encipherOnly = (b2 & 0x01) === 0x01;
1536 e.decipherOnly = (b3 & 0x80) === 0x80;
1537 } else if(e.name === 'basicConstraints') {
1538 // handle basic constraints
1539 // get value as SEQUENCE
1540 var ev = asn1.fromDer(e.value);
1541 // get cA BOOLEAN flag (defaults to false)
1542 if(ev.value.length > 0 && ev.value[0].type === asn1.Type.BOOLEAN) {
1543 e.cA = (ev.value[0].value.charCodeAt(0) !== 0x00);
1544 } else {
1545 e.cA = false;
1546 }
1547 // get path length constraint
1548 var value = null;
1549 if(ev.value.length > 0 && ev.value[0].type === asn1.Type.INTEGER) {
1550 value = ev.value[0].value;
1551 } else if(ev.value.length > 1) {
1552 value = ev.value[1].value;
1553 }
1554 if(value !== null) {
1555 e.pathLenConstraint = asn1.derToInteger(value);
1556 }
1557 } else if(e.name === 'extKeyUsage') {
1558 // handle extKeyUsage
1559 // value is a SEQUENCE of OIDs
1560 var ev = asn1.fromDer(e.value);
1561 for(var vi = 0; vi < ev.value.length; ++vi) {
1562 var oid = asn1.derToOid(ev.value[vi].value);
1563 if(oid in oids) {
1564 e[oids[oid]] = true;
1565 } else {
1566 e[oid] = true;
1567 }
1568 }
1569 } else if(e.name === 'nsCertType') {
1570 // handle nsCertType
1571 // get value as BIT STRING
1572 var ev = asn1.fromDer(e.value);
1573 var b2 = 0x00;
1574 if(ev.value.length > 1) {
1575 // skip first byte, just indicates unused bits which
1576 // will be padded with 0s anyway
1577 // get bytes with flag bits
1578 b2 = ev.value.charCodeAt(1);
1579 }
1580 // set flags
1581 e.client = (b2 & 0x80) === 0x80;
1582 e.server = (b2 & 0x40) === 0x40;
1583 e.email = (b2 & 0x20) === 0x20;
1584 e.objsign = (b2 & 0x10) === 0x10;
1585 e.reserved = (b2 & 0x08) === 0x08;
1586 e.sslCA = (b2 & 0x04) === 0x04;
1587 e.emailCA = (b2 & 0x02) === 0x02;
1588 e.objCA = (b2 & 0x01) === 0x01;
1589 } else if(
1590 e.name === 'subjectAltName' ||
1591 e.name === 'issuerAltName') {
1592 // handle subjectAltName/issuerAltName
1593 e.altNames = [];
1594
1595 // ev is a SYNTAX SEQUENCE
1596 var gn;
1597 var ev = asn1.fromDer(e.value);
1598 for(var n = 0; n < ev.value.length; ++n) {
1599 // get GeneralName
1600 gn = ev.value[n];
1601
1602 var altName = {
1603 type: gn.type,
1604 value: gn.value
1605 };
1606 e.altNames.push(altName);
1607
1608 // Note: Support for types 1,2,6,7,8
1609 switch(gn.type) {
1610 // rfc822Name
1611 case 1:
1612 // dNSName
1613 case 2:
1614 // uniformResourceIdentifier (URI)
1615 case 6:
1616 break;
1617 // IPAddress
1618 case 7:
1619 // convert to IPv4/IPv6 string representation
1620 altName.ip = forge.util.bytesToIP(gn.value);
1621 break;
1622 // registeredID
1623 case 8:
1624 altName.oid = asn1.derToOid(gn.value);
1625 break;
1626 default:
1627 // unsupported
1628 }
1629 }
1630 } else if(e.name === 'subjectKeyIdentifier') {
1631 // value is an OCTETSTRING w/the hash of the key-type specific
1632 // public key structure (eg: RSAPublicKey)
1633 var ev = asn1.fromDer(e.value);
1634 e.subjectKeyIdentifier = forge.util.bytesToHex(ev.value);
1635 }
1636 }
1637 return e;
1638};
1639
1640/**
1641 * Converts a PKCS#10 certification request (CSR) from an ASN.1 object.
1642 *
1643 * Note: If the certification request is to be verified then compute hash
1644 * should be set to true. There is currently no implementation for converting
1645 * a certificate back to ASN.1 so the CertificationRequestInfo part of the
1646 * ASN.1 object needs to be scanned before the csr object is created.
1647 *
1648 * @param obj the asn1 representation of a PKCS#10 certification request (CSR).
1649 * @param computeHash true to compute the hash for verification.
1650 *
1651 * @return the certification request (CSR).
1652 */
1653pki.certificationRequestFromAsn1 = function(obj, computeHash) {
1654 // validate certification request and capture data
1655 var capture = {};
1656 var errors = [];
1657 if(!asn1.validate(obj, certificationRequestValidator, capture, errors)) {
1658 var error = new Error('Cannot read PKCS#10 certificate request. ' +
1659 'ASN.1 object is not a PKCS#10 CertificationRequest.');
1660 error.errors = errors;
1661 throw error;
1662 }
1663
1664 // get oid
1665 var oid = asn1.derToOid(capture.publicKeyOid);
1666 if(oid !== pki.oids.rsaEncryption) {
1667 throw new Error('Cannot read public key. OID is not RSA.');
1668 }
1669
1670 // create certification request
1671 var csr = pki.createCertificationRequest();
1672 csr.version = capture.csrVersion ? capture.csrVersion.charCodeAt(0) : 0;
1673 csr.signatureOid = forge.asn1.derToOid(capture.csrSignatureOid);
1674 csr.signatureParameters = _readSignatureParameters(
1675 csr.signatureOid, capture.csrSignatureParams, true);
1676 csr.siginfo.algorithmOid = forge.asn1.derToOid(capture.csrSignatureOid);
1677 csr.siginfo.parameters = _readSignatureParameters(
1678 csr.siginfo.algorithmOid, capture.csrSignatureParams, false);
1679 csr.signature = capture.csrSignature;
1680
1681 // keep CertificationRequestInfo to preserve signature when exporting
1682 csr.certificationRequestInfo = capture.certificationRequestInfo;
1683
1684 if(computeHash) {
1685 // create digest for OID signature type
1686 csr.md = _createSignatureDigest({
1687 signatureOid: csr.signatureOid,
1688 type: 'certification request'
1689 });
1690
1691 // produce DER formatted CertificationRequestInfo and digest it
1692 var bytes = asn1.toDer(csr.certificationRequestInfo);
1693 csr.md.update(bytes.getBytes());
1694 }
1695
1696 // handle subject, build subject message digest
1697 var smd = forge.md.sha1.create();
1698 csr.subject.getField = function(sn) {
1699 return _getAttribute(csr.subject, sn);
1700 };
1701 csr.subject.addField = function(attr) {
1702 _fillMissingFields([attr]);
1703 csr.subject.attributes.push(attr);
1704 };
1705 csr.subject.attributes = pki.RDNAttributesAsArray(
1706 capture.certificationRequestInfoSubject, smd);
1707 csr.subject.hash = smd.digest().toHex();
1708
1709 // convert RSA public key from ASN.1
1710 csr.publicKey = pki.publicKeyFromAsn1(capture.subjectPublicKeyInfo);
1711
1712 // convert attributes from ASN.1
1713 csr.getAttribute = function(sn) {
1714 return _getAttribute(csr, sn);
1715 };
1716 csr.addAttribute = function(attr) {
1717 _fillMissingFields([attr]);
1718 csr.attributes.push(attr);
1719 };
1720 csr.attributes = pki.CRIAttributesAsArray(
1721 capture.certificationRequestInfoAttributes || []);
1722
1723 return csr;
1724};
1725
1726/**
1727 * Creates an empty certification request (a CSR or certificate signing
1728 * request). Once created, its public key and attributes can be set and then
1729 * it can be signed.
1730 *
1731 * @return the empty certification request.
1732 */
1733pki.createCertificationRequest = function() {
1734 var csr = {};
1735 csr.version = 0x00;
1736 csr.signatureOid = null;
1737 csr.signature = null;
1738 csr.siginfo = {};
1739 csr.siginfo.algorithmOid = null;
1740
1741 csr.subject = {};
1742 csr.subject.getField = function(sn) {
1743 return _getAttribute(csr.subject, sn);
1744 };
1745 csr.subject.addField = function(attr) {
1746 _fillMissingFields([attr]);
1747 csr.subject.attributes.push(attr);
1748 };
1749 csr.subject.attributes = [];
1750 csr.subject.hash = null;
1751
1752 csr.publicKey = null;
1753 csr.attributes = [];
1754 csr.getAttribute = function(sn) {
1755 return _getAttribute(csr, sn);
1756 };
1757 csr.addAttribute = function(attr) {
1758 _fillMissingFields([attr]);
1759 csr.attributes.push(attr);
1760 };
1761 csr.md = null;
1762
1763 /**
1764 * Sets the subject of this certification request.
1765 *
1766 * @param attrs the array of subject attributes to use.
1767 */
1768 csr.setSubject = function(attrs) {
1769 // set new attributes
1770 _fillMissingFields(attrs);
1771 csr.subject.attributes = attrs;
1772 csr.subject.hash = null;
1773 };
1774
1775 /**
1776 * Sets the attributes of this certification request.
1777 *
1778 * @param attrs the array of attributes to use.
1779 */
1780 csr.setAttributes = function(attrs) {
1781 // set new attributes
1782 _fillMissingFields(attrs);
1783 csr.attributes = attrs;
1784 };
1785
1786 /**
1787 * Signs this certification request using the given private key.
1788 *
1789 * @param key the private key to sign with.
1790 * @param md the message digest object to use (defaults to forge.md.sha1).
1791 */
1792 csr.sign = function(key, md) {
1793 // TODO: get signature OID from private key
1794 csr.md = md || forge.md.sha1.create();
1795 var algorithmOid = oids[csr.md.algorithm + 'WithRSAEncryption'];
1796 if(!algorithmOid) {
1797 var error = new Error('Could not compute certification request digest. ' +
1798 'Unknown message digest algorithm OID.');
1799 error.algorithm = csr.md.algorithm;
1800 throw error;
1801 }
1802 csr.signatureOid = csr.siginfo.algorithmOid = algorithmOid;
1803
1804 // get CertificationRequestInfo, convert to DER
1805 csr.certificationRequestInfo = pki.getCertificationRequestInfo(csr);
1806 var bytes = asn1.toDer(csr.certificationRequestInfo);
1807
1808 // digest and sign
1809 csr.md.update(bytes.getBytes());
1810 csr.signature = key.sign(csr.md);
1811 };
1812
1813 /**
1814 * Attempts verify the signature on the passed certification request using
1815 * its public key.
1816 *
1817 * A CSR that has been exported to a file in PEM format can be verified using
1818 * OpenSSL using this command:
1819 *
1820 * openssl req -in <the-csr-pem-file> -verify -noout -text
1821 *
1822 * @return true if verified, false if not.
1823 */
1824 csr.verify = function() {
1825 var rval = false;
1826
1827 var md = csr.md;
1828 if(md === null) {
1829 md = _createSignatureDigest({
1830 signatureOid: csr.signatureOid,
1831 type: 'certification request'
1832 });
1833
1834 // produce DER formatted CertificationRequestInfo and digest it
1835 var cri = csr.certificationRequestInfo ||
1836 pki.getCertificationRequestInfo(csr);
1837 var bytes = asn1.toDer(cri);
1838 md.update(bytes.getBytes());
1839 }
1840
1841 if(md !== null) {
1842 rval = _verifySignature({
1843 certificate: csr, md: md, signature: csr.signature
1844 });
1845 }
1846
1847 return rval;
1848 };
1849
1850 return csr;
1851};
1852
1853/**
1854 * Converts an X.509 subject or issuer to an ASN.1 RDNSequence.
1855 *
1856 * @param obj the subject or issuer (distinguished name).
1857 *
1858 * @return the ASN.1 RDNSequence.
1859 */
1860function _dnToAsn1(obj) {
1861 // create an empty RDNSequence
1862 var rval = asn1.create(
1863 asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
1864
1865 // iterate over attributes
1866 var attr, set;
1867 var attrs = obj.attributes;
1868 for(var i = 0; i < attrs.length; ++i) {
1869 attr = attrs[i];
1870 var value = attr.value;
1871
1872 // reuse tag class for attribute value if available
1873 var valueTagClass = asn1.Type.PRINTABLESTRING;
1874 if('valueTagClass' in attr) {
1875 valueTagClass = attr.valueTagClass;
1876
1877 if(valueTagClass === asn1.Type.UTF8) {
1878 value = forge.util.encodeUtf8(value);
1879 }
1880 // FIXME: handle more encodings
1881 }
1882
1883 // create a RelativeDistinguishedName set
1884 // each value in the set is an AttributeTypeAndValue first
1885 // containing the type (an OID) and second the value
1886 set = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [
1887 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
1888 // AttributeType
1889 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
1890 asn1.oidToDer(attr.type).getBytes()),
1891 // AttributeValue
1892 asn1.create(asn1.Class.UNIVERSAL, valueTagClass, false, value)
1893 ])
1894 ]);
1895 rval.value.push(set);
1896 }
1897
1898 return rval;
1899}
1900
1901/**
1902 * Gets all printable attributes (typically of an issuer or subject) in a
1903 * simplified JSON format for display.
1904 *
1905 * @param attrs the attributes.
1906 *
1907 * @return the JSON for display.
1908 */
1909function _getAttributesAsJson(attrs) {
1910 var rval = {};
1911 for(var i = 0; i < attrs.length; ++i) {
1912 var attr = attrs[i];
1913 if(attr.shortName && (
1914 attr.valueTagClass === asn1.Type.UTF8 ||
1915 attr.valueTagClass === asn1.Type.PRINTABLESTRING ||
1916 attr.valueTagClass === asn1.Type.IA5STRING)) {
1917 var value = attr.value;
1918 if(attr.valueTagClass === asn1.Type.UTF8) {
1919 value = forge.util.encodeUtf8(attr.value);
1920 }
1921 if(!(attr.shortName in rval)) {
1922 rval[attr.shortName] = value;
1923 } else if(forge.util.isArray(rval[attr.shortName])) {
1924 rval[attr.shortName].push(value);
1925 } else {
1926 rval[attr.shortName] = [rval[attr.shortName], value];
1927 }
1928 }
1929 }
1930 return rval;
1931}
1932
1933/**
1934 * Fills in missing fields in attributes.
1935 *
1936 * @param attrs the attributes to fill missing fields in.
1937 */
1938function _fillMissingFields(attrs) {
1939 var attr;
1940 for(var i = 0; i < attrs.length; ++i) {
1941 attr = attrs[i];
1942
1943 // populate missing name
1944 if(typeof attr.name === 'undefined') {
1945 if(attr.type && attr.type in pki.oids) {
1946 attr.name = pki.oids[attr.type];
1947 } else if(attr.shortName && attr.shortName in _shortNames) {
1948 attr.name = pki.oids[_shortNames[attr.shortName]];
1949 }
1950 }
1951
1952 // populate missing type (OID)
1953 if(typeof attr.type === 'undefined') {
1954 if(attr.name && attr.name in pki.oids) {
1955 attr.type = pki.oids[attr.name];
1956 } else {
1957 var error = new Error('Attribute type not specified.');
1958 error.attribute = attr;
1959 throw error;
1960 }
1961 }
1962
1963 // populate missing shortname
1964 if(typeof attr.shortName === 'undefined') {
1965 if(attr.name && attr.name in _shortNames) {
1966 attr.shortName = _shortNames[attr.name];
1967 }
1968 }
1969
1970 // convert extensions to value
1971 if(attr.type === oids.extensionRequest) {
1972 attr.valueConstructed = true;
1973 attr.valueTagClass = asn1.Type.SEQUENCE;
1974 if(!attr.value && attr.extensions) {
1975 attr.value = [];
1976 for(var ei = 0; ei < attr.extensions.length; ++ei) {
1977 attr.value.push(pki.certificateExtensionToAsn1(
1978 _fillMissingExtensionFields(attr.extensions[ei])));
1979 }
1980 }
1981 }
1982
1983 if(typeof attr.value === 'undefined') {
1984 var error = new Error('Attribute value not specified.');
1985 error.attribute = attr;
1986 throw error;
1987 }
1988 }
1989}
1990
1991/**
1992 * Fills in missing fields in certificate extensions.
1993 *
1994 * @param e the extension.
1995 * @param [options] the options to use.
1996 * [cert] the certificate the extensions are for.
1997 *
1998 * @return the extension.
1999 */
2000function _fillMissingExtensionFields(e, options) {
2001 options = options || {};
2002
2003 // populate missing name
2004 if(typeof e.name === 'undefined') {
2005 if(e.id && e.id in pki.oids) {
2006 e.name = pki.oids[e.id];
2007 }
2008 }
2009
2010 // populate missing id
2011 if(typeof e.id === 'undefined') {
2012 if(e.name && e.name in pki.oids) {
2013 e.id = pki.oids[e.name];
2014 } else {
2015 var error = new Error('Extension ID not specified.');
2016 error.extension = e;
2017 throw error;
2018 }
2019 }
2020
2021 if(typeof e.value !== 'undefined') {
2022 return e;
2023 }
2024
2025 // handle missing value:
2026
2027 // value is a BIT STRING
2028 if(e.name === 'keyUsage') {
2029 // build flags
2030 var unused = 0;
2031 var b2 = 0x00;
2032 var b3 = 0x00;
2033 if(e.digitalSignature) {
2034 b2 |= 0x80;
2035 unused = 7;
2036 }
2037 if(e.nonRepudiation) {
2038 b2 |= 0x40;
2039 unused = 6;
2040 }
2041 if(e.keyEncipherment) {
2042 b2 |= 0x20;
2043 unused = 5;
2044 }
2045 if(e.dataEncipherment) {
2046 b2 |= 0x10;
2047 unused = 4;
2048 }
2049 if(e.keyAgreement) {
2050 b2 |= 0x08;
2051 unused = 3;
2052 }
2053 if(e.keyCertSign) {
2054 b2 |= 0x04;
2055 unused = 2;
2056 }
2057 if(e.cRLSign) {
2058 b2 |= 0x02;
2059 unused = 1;
2060 }
2061 if(e.encipherOnly) {
2062 b2 |= 0x01;
2063 unused = 0;
2064 }
2065 if(e.decipherOnly) {
2066 b3 |= 0x80;
2067 unused = 7;
2068 }
2069
2070 // create bit string
2071 var value = String.fromCharCode(unused);
2072 if(b3 !== 0) {
2073 value += String.fromCharCode(b2) + String.fromCharCode(b3);
2074 } else if(b2 !== 0) {
2075 value += String.fromCharCode(b2);
2076 }
2077 e.value = asn1.create(
2078 asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, value);
2079 } else if(e.name === 'basicConstraints') {
2080 // basicConstraints is a SEQUENCE
2081 e.value = asn1.create(
2082 asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2083 // cA BOOLEAN flag defaults to false
2084 if(e.cA) {
2085 e.value.value.push(asn1.create(
2086 asn1.Class.UNIVERSAL, asn1.Type.BOOLEAN, false,
2087 String.fromCharCode(0xFF)));
2088 }
2089 if('pathLenConstraint' in e) {
2090 e.value.value.push(asn1.create(
2091 asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
2092 asn1.integerToDer(e.pathLenConstraint).getBytes()));
2093 }
2094 } else if(e.name === 'extKeyUsage') {
2095 // extKeyUsage is a SEQUENCE of OIDs
2096 e.value = asn1.create(
2097 asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2098 var seq = e.value.value;
2099 for(var key in e) {
2100 if(e[key] !== true) {
2101 continue;
2102 }
2103 // key is name in OID map
2104 if(key in oids) {
2105 seq.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID,
2106 false, asn1.oidToDer(oids[key]).getBytes()));
2107 } else if(key.indexOf('.') !== -1) {
2108 // assume key is an OID
2109 seq.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID,
2110 false, asn1.oidToDer(key).getBytes()));
2111 }
2112 }
2113 } else if(e.name === 'nsCertType') {
2114 // nsCertType is a BIT STRING
2115 // build flags
2116 var unused = 0;
2117 var b2 = 0x00;
2118
2119 if(e.client) {
2120 b2 |= 0x80;
2121 unused = 7;
2122 }
2123 if(e.server) {
2124 b2 |= 0x40;
2125 unused = 6;
2126 }
2127 if(e.email) {
2128 b2 |= 0x20;
2129 unused = 5;
2130 }
2131 if(e.objsign) {
2132 b2 |= 0x10;
2133 unused = 4;
2134 }
2135 if(e.reserved) {
2136 b2 |= 0x08;
2137 unused = 3;
2138 }
2139 if(e.sslCA) {
2140 b2 |= 0x04;
2141 unused = 2;
2142 }
2143 if(e.emailCA) {
2144 b2 |= 0x02;
2145 unused = 1;
2146 }
2147 if(e.objCA) {
2148 b2 |= 0x01;
2149 unused = 0;
2150 }
2151
2152 // create bit string
2153 var value = String.fromCharCode(unused);
2154 if(b2 !== 0) {
2155 value += String.fromCharCode(b2);
2156 }
2157 e.value = asn1.create(
2158 asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, value);
2159 } else if(e.name === 'subjectAltName' || e.name === 'issuerAltName') {
2160 // SYNTAX SEQUENCE
2161 e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2162
2163 var altName;
2164 for(var n = 0; n < e.altNames.length; ++n) {
2165 altName = e.altNames[n];
2166 var value = altName.value;
2167 // handle IP
2168 if(altName.type === 7 && altName.ip) {
2169 value = forge.util.bytesFromIP(altName.ip);
2170 if(value === null) {
2171 var error = new Error(
2172 'Extension "ip" value is not a valid IPv4 or IPv6 address.');
2173 error.extension = e;
2174 throw error;
2175 }
2176 } else if(altName.type === 8) {
2177 // handle OID
2178 if(altName.oid) {
2179 value = asn1.oidToDer(asn1.oidToDer(altName.oid));
2180 } else {
2181 // deprecated ... convert value to OID
2182 value = asn1.oidToDer(value);
2183 }
2184 }
2185 e.value.value.push(asn1.create(
2186 asn1.Class.CONTEXT_SPECIFIC, altName.type, false,
2187 value));
2188 }
2189 } else if(e.name === 'nsComment' && options.cert) {
2190 // sanity check value is ASCII (req'd) and not too big
2191 if(!(/^[\x00-\x7F]*$/.test(e.comment)) ||
2192 (e.comment.length < 1) || (e.comment.length > 128)) {
2193 throw new Error('Invalid "nsComment" content.');
2194 }
2195 // IA5STRING opaque comment
2196 e.value = asn1.create(
2197 asn1.Class.UNIVERSAL, asn1.Type.IA5STRING, false, e.comment);
2198 } else if(e.name === 'subjectKeyIdentifier' && options.cert) {
2199 var ski = options.cert.generateSubjectKeyIdentifier();
2200 e.subjectKeyIdentifier = ski.toHex();
2201 // OCTETSTRING w/digest
2202 e.value = asn1.create(
2203 asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, ski.getBytes());
2204 } else if(e.name === 'authorityKeyIdentifier' && options.cert) {
2205 // SYNTAX SEQUENCE
2206 e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2207 var seq = e.value.value;
2208
2209 if(e.keyIdentifier) {
2210 var keyIdentifier = (e.keyIdentifier === true ?
2211 options.cert.generateSubjectKeyIdentifier().getBytes() :
2212 e.keyIdentifier);
2213 seq.push(
2214 asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, false, keyIdentifier));
2215 }
2216
2217 if(e.authorityCertIssuer) {
2218 var authorityCertIssuer = [
2219 asn1.create(asn1.Class.CONTEXT_SPECIFIC, 4, true, [
2220 _dnToAsn1(e.authorityCertIssuer === true ?
2221 options.cert.issuer : e.authorityCertIssuer)
2222 ])
2223 ];
2224 seq.push(
2225 asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, authorityCertIssuer));
2226 }
2227
2228 if(e.serialNumber) {
2229 var serialNumber = forge.util.hexToBytes(e.serialNumber === true ?
2230 options.cert.serialNumber : e.serialNumber);
2231 seq.push(
2232 asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, false, serialNumber));
2233 }
2234 } else if(e.name === 'cRLDistributionPoints') {
2235 e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2236 var seq = e.value.value;
2237
2238 // Create sub SEQUENCE of DistributionPointName
2239 var subSeq = asn1.create(
2240 asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2241
2242 // Create fullName CHOICE
2243 var fullNameGeneralNames = asn1.create(
2244 asn1.Class.CONTEXT_SPECIFIC, 0, true, []);
2245 var altName;
2246 for(var n = 0; n < e.altNames.length; ++n) {
2247 altName = e.altNames[n];
2248 var value = altName.value;
2249 // handle IP
2250 if(altName.type === 7 && altName.ip) {
2251 value = forge.util.bytesFromIP(altName.ip);
2252 if(value === null) {
2253 var error = new Error(
2254 'Extension "ip" value is not a valid IPv4 or IPv6 address.');
2255 error.extension = e;
2256 throw error;
2257 }
2258 } else if(altName.type === 8) {
2259 // handle OID
2260 if(altName.oid) {
2261 value = asn1.oidToDer(asn1.oidToDer(altName.oid));
2262 } else {
2263 // deprecated ... convert value to OID
2264 value = asn1.oidToDer(value);
2265 }
2266 }
2267 fullNameGeneralNames.value.push(asn1.create(
2268 asn1.Class.CONTEXT_SPECIFIC, altName.type, false,
2269 value));
2270 }
2271
2272 // Add to the parent SEQUENCE
2273 subSeq.value.push(asn1.create(
2274 asn1.Class.CONTEXT_SPECIFIC, 0, true, [fullNameGeneralNames]));
2275 seq.push(subSeq);
2276 }
2277
2278 // ensure value has been defined by now
2279 if(typeof e.value === 'undefined') {
2280 var error = new Error('Extension value not specified.');
2281 error.extension = e;
2282 throw error;
2283 }
2284
2285 return e;
2286}
2287
2288/**
2289 * Convert signature parameters object to ASN.1
2290 *
2291 * @param {String} oid Signature algorithm OID
2292 * @param params The signature parameters object
2293 * @return ASN.1 object representing signature parameters
2294 */
2295function _signatureParametersToAsn1(oid, params) {
2296 switch(oid) {
2297 case oids['RSASSA-PSS']:
2298 var parts = [];
2299
2300 if(params.hash.algorithmOid !== undefined) {
2301 parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
2302 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2303 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2304 asn1.oidToDer(params.hash.algorithmOid).getBytes()),
2305 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
2306 ])
2307 ]));
2308 }
2309
2310 if(params.mgf.algorithmOid !== undefined) {
2311 parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
2312 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2313 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2314 asn1.oidToDer(params.mgf.algorithmOid).getBytes()),
2315 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2316 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2317 asn1.oidToDer(params.mgf.hash.algorithmOid).getBytes()),
2318 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
2319 ])
2320 ])
2321 ]));
2322 }
2323
2324 if(params.saltLength !== undefined) {
2325 parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [
2326 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
2327 asn1.integerToDer(params.saltLength).getBytes())
2328 ]));
2329 }
2330
2331 return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, parts);
2332
2333 default:
2334 return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '');
2335 }
2336}
2337
2338/**
2339 * Converts a certification request's attributes to an ASN.1 set of
2340 * CRIAttributes.
2341 *
2342 * @param csr certification request.
2343 *
2344 * @return the ASN.1 set of CRIAttributes.
2345 */
2346function _CRIAttributesToAsn1(csr) {
2347 // create an empty context-specific container
2348 var rval = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, []);
2349
2350 // no attributes, return empty container
2351 if(csr.attributes.length === 0) {
2352 return rval;
2353 }
2354
2355 // each attribute has a sequence with a type and a set of values
2356 var attrs = csr.attributes;
2357 for(var i = 0; i < attrs.length; ++i) {
2358 var attr = attrs[i];
2359 var value = attr.value;
2360
2361 // reuse tag class for attribute value if available
2362 var valueTagClass = asn1.Type.UTF8;
2363 if('valueTagClass' in attr) {
2364 valueTagClass = attr.valueTagClass;
2365 }
2366 if(valueTagClass === asn1.Type.UTF8) {
2367 value = forge.util.encodeUtf8(value);
2368 }
2369 var valueConstructed = false;
2370 if('valueConstructed' in attr) {
2371 valueConstructed = attr.valueConstructed;
2372 }
2373 // FIXME: handle more encodings
2374
2375 // create a RelativeDistinguishedName set
2376 // each value in the set is an AttributeTypeAndValue first
2377 // containing the type (an OID) and second the value
2378 var seq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2379 // AttributeType
2380 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2381 asn1.oidToDer(attr.type).getBytes()),
2382 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [
2383 // AttributeValue
2384 asn1.create(
2385 asn1.Class.UNIVERSAL, valueTagClass, valueConstructed, value)
2386 ])
2387 ]);
2388 rval.value.push(seq);
2389 }
2390
2391 return rval;
2392}
2393
2394var jan_1_1950 = new Date('1950-01-01T00:00:00Z');
2395var jan_1_2050 = new Date('2050-01-01T00:00:00Z');
2396
2397/**
2398 * Converts a Date object to ASN.1
2399 * Handles the different format before and after 1st January 2050
2400 *
2401 * @param date date object.
2402 *
2403 * @return the ASN.1 object representing the date.
2404 */
2405function _dateToAsn1(date) {
2406 if(date >= jan_1_1950 && date < jan_1_2050) {
2407 return asn1.create(
2408 asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false,
2409 asn1.dateToUtcTime(date));
2410 } else {
2411 return asn1.create(
2412 asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false,
2413 asn1.dateToGeneralizedTime(date));
2414 }
2415}
2416
2417/**
2418 * Gets the ASN.1 TBSCertificate part of an X.509v3 certificate.
2419 *
2420 * @param cert the certificate.
2421 *
2422 * @return the asn1 TBSCertificate.
2423 */
2424pki.getTBSCertificate = function(cert) {
2425 // TBSCertificate
2426 var notBefore = _dateToAsn1(cert.validity.notBefore);
2427 var notAfter = _dateToAsn1(cert.validity.notAfter);
2428 var tbs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2429 // version
2430 asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
2431 // integer
2432 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
2433 asn1.integerToDer(cert.version).getBytes())
2434 ]),
2435 // serialNumber
2436 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
2437 forge.util.hexToBytes(cert.serialNumber)),
2438 // signature
2439 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2440 // algorithm
2441 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2442 asn1.oidToDer(cert.siginfo.algorithmOid).getBytes()),
2443 // parameters
2444 _signatureParametersToAsn1(
2445 cert.siginfo.algorithmOid, cert.siginfo.parameters)
2446 ]),
2447 // issuer
2448 _dnToAsn1(cert.issuer),
2449 // validity
2450 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2451 notBefore,
2452 notAfter
2453 ]),
2454 // subject
2455 _dnToAsn1(cert.subject),
2456 // SubjectPublicKeyInfo
2457 pki.publicKeyToAsn1(cert.publicKey)
2458 ]);
2459
2460 if(cert.issuer.uniqueId) {
2461 // issuerUniqueID (optional)
2462 tbs.value.push(
2463 asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
2464 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false,
2465 // TODO: support arbitrary bit length ids
2466 String.fromCharCode(0x00) +
2467 cert.issuer.uniqueId
2468 )
2469 ])
2470 );
2471 }
2472 if(cert.subject.uniqueId) {
2473 // subjectUniqueID (optional)
2474 tbs.value.push(
2475 asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [
2476 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false,
2477 // TODO: support arbitrary bit length ids
2478 String.fromCharCode(0x00) +
2479 cert.subject.uniqueId
2480 )
2481 ])
2482 );
2483 }
2484
2485 if(cert.extensions.length > 0) {
2486 // extensions (optional)
2487 tbs.value.push(pki.certificateExtensionsToAsn1(cert.extensions));
2488 }
2489
2490 return tbs;
2491};
2492
2493/**
2494 * Gets the ASN.1 CertificationRequestInfo part of a
2495 * PKCS#10 CertificationRequest.
2496 *
2497 * @param csr the certification request.
2498 *
2499 * @return the asn1 CertificationRequestInfo.
2500 */
2501pki.getCertificationRequestInfo = function(csr) {
2502 // CertificationRequestInfo
2503 var cri = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2504 // version
2505 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
2506 asn1.integerToDer(csr.version).getBytes()),
2507 // subject
2508 _dnToAsn1(csr.subject),
2509 // SubjectPublicKeyInfo
2510 pki.publicKeyToAsn1(csr.publicKey),
2511 // attributes
2512 _CRIAttributesToAsn1(csr)
2513 ]);
2514
2515 return cri;
2516};
2517
2518/**
2519 * Converts a DistinguishedName (subject or issuer) to an ASN.1 object.
2520 *
2521 * @param dn the DistinguishedName.
2522 *
2523 * @return the asn1 representation of a DistinguishedName.
2524 */
2525pki.distinguishedNameToAsn1 = function(dn) {
2526 return _dnToAsn1(dn);
2527};
2528
2529/**
2530 * Converts an X.509v3 RSA certificate to an ASN.1 object.
2531 *
2532 * @param cert the certificate.
2533 *
2534 * @return the asn1 representation of an X.509v3 RSA certificate.
2535 */
2536pki.certificateToAsn1 = function(cert) {
2537 // prefer cached TBSCertificate over generating one
2538 var tbsCertificate = cert.tbsCertificate || pki.getTBSCertificate(cert);
2539
2540 // Certificate
2541 return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2542 // TBSCertificate
2543 tbsCertificate,
2544 // AlgorithmIdentifier (signature algorithm)
2545 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2546 // algorithm
2547 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2548 asn1.oidToDer(cert.signatureOid).getBytes()),
2549 // parameters
2550 _signatureParametersToAsn1(cert.signatureOid, cert.signatureParameters)
2551 ]),
2552 // SignatureValue
2553 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false,
2554 String.fromCharCode(0x00) + cert.signature)
2555 ]);
2556};
2557
2558/**
2559 * Converts X.509v3 certificate extensions to ASN.1.
2560 *
2561 * @param exts the extensions to convert.
2562 *
2563 * @return the extensions in ASN.1 format.
2564 */
2565pki.certificateExtensionsToAsn1 = function(exts) {
2566 // create top-level extension container
2567 var rval = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 3, true, []);
2568
2569 // create extension sequence (stores a sequence for each extension)
2570 var seq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2571 rval.value.push(seq);
2572
2573 for(var i = 0; i < exts.length; ++i) {
2574 seq.value.push(pki.certificateExtensionToAsn1(exts[i]));
2575 }
2576
2577 return rval;
2578};
2579
2580/**
2581 * Converts a single certificate extension to ASN.1.
2582 *
2583 * @param ext the extension to convert.
2584 *
2585 * @return the extension in ASN.1 format.
2586 */
2587pki.certificateExtensionToAsn1 = function(ext) {
2588 // create a sequence for each extension
2589 var extseq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2590
2591 // extnID (OID)
2592 extseq.value.push(asn1.create(
2593 asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2594 asn1.oidToDer(ext.id).getBytes()));
2595
2596 // critical defaults to false
2597 if(ext.critical) {
2598 // critical BOOLEAN DEFAULT FALSE
2599 extseq.value.push(asn1.create(
2600 asn1.Class.UNIVERSAL, asn1.Type.BOOLEAN, false,
2601 String.fromCharCode(0xFF)));
2602 }
2603
2604 var value = ext.value;
2605 if(typeof ext.value !== 'string') {
2606 // value is asn.1
2607 value = asn1.toDer(value).getBytes();
2608 }
2609
2610 // extnValue (OCTET STRING)
2611 extseq.value.push(asn1.create(
2612 asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, value));
2613
2614 return extseq;
2615};
2616
2617/**
2618 * Converts a PKCS#10 certification request to an ASN.1 object.
2619 *
2620 * @param csr the certification request.
2621 *
2622 * @return the asn1 representation of a certification request.
2623 */
2624pki.certificationRequestToAsn1 = function(csr) {
2625 // prefer cached CertificationRequestInfo over generating one
2626 var cri = csr.certificationRequestInfo ||
2627 pki.getCertificationRequestInfo(csr);
2628
2629 // Certificate
2630 return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2631 // CertificationRequestInfo
2632 cri,
2633 // AlgorithmIdentifier (signature algorithm)
2634 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2635 // algorithm
2636 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2637 asn1.oidToDer(csr.signatureOid).getBytes()),
2638 // parameters
2639 _signatureParametersToAsn1(csr.signatureOid, csr.signatureParameters)
2640 ]),
2641 // signature
2642 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false,
2643 String.fromCharCode(0x00) + csr.signature)
2644 ]);
2645};
2646
2647/**
2648 * Creates a CA store.
2649 *
2650 * @param certs an optional array of certificate objects or PEM-formatted
2651 * certificate strings to add to the CA store.
2652 *
2653 * @return the CA store.
2654 */
2655pki.createCaStore = function(certs) {
2656 // create CA store
2657 var caStore = {
2658 // stored certificates
2659 certs: {}
2660 };
2661
2662 /**
2663 * Gets the certificate that issued the passed certificate or its
2664 * 'parent'.
2665 *
2666 * @param cert the certificate to get the parent for.
2667 *
2668 * @return the parent certificate or null if none was found.
2669 */
2670 caStore.getIssuer = function(cert) {
2671 var rval = getBySubject(cert.issuer);
2672
2673 // see if there are multiple matches
2674 /*if(forge.util.isArray(rval)) {
2675 // TODO: resolve multiple matches by checking
2676 // authorityKey/subjectKey/issuerUniqueID/other identifiers, etc.
2677 // FIXME: or alternatively do authority key mapping
2678 // if possible (X.509v1 certs can't work?)
2679 throw new Error('Resolving multiple issuer matches not implemented yet.');
2680 }*/
2681
2682 return rval;
2683 };
2684
2685 /**
2686 * Adds a trusted certificate to the store.
2687 *
2688 * @param cert the certificate to add as a trusted certificate (either a
2689 * pki.certificate object or a PEM-formatted certificate).
2690 */
2691 caStore.addCertificate = function(cert) {
2692 // convert from pem if necessary
2693 if(typeof cert === 'string') {
2694 cert = forge.pki.certificateFromPem(cert);
2695 }
2696
2697 ensureSubjectHasHash(cert.subject);
2698
2699 if(!caStore.hasCertificate(cert)) { // avoid duplicate certificates in store
2700 if(cert.subject.hash in caStore.certs) {
2701 // subject hash already exists, append to array
2702 var tmp = caStore.certs[cert.subject.hash];
2703 if(!forge.util.isArray(tmp)) {
2704 tmp = [tmp];
2705 }
2706 tmp.push(cert);
2707 caStore.certs[cert.subject.hash] = tmp;
2708 } else {
2709 caStore.certs[cert.subject.hash] = cert;
2710 }
2711 }
2712 };
2713
2714 /**
2715 * Checks to see if the given certificate is in the store.
2716 *
2717 * @param cert the certificate to check (either a pki.certificate or a
2718 * PEM-formatted certificate).
2719 *
2720 * @return true if the certificate is in the store, false if not.
2721 */
2722 caStore.hasCertificate = function(cert) {
2723 // convert from pem if necessary
2724 if(typeof cert === 'string') {
2725 cert = forge.pki.certificateFromPem(cert);
2726 }
2727
2728 var match = getBySubject(cert.subject);
2729 if(!match) {
2730 return false;
2731 }
2732 if(!forge.util.isArray(match)) {
2733 match = [match];
2734 }
2735 // compare DER-encoding of certificates
2736 var der1 = asn1.toDer(pki.certificateToAsn1(cert)).getBytes();
2737 for(var i = 0; i < match.length; ++i) {
2738 var der2 = asn1.toDer(pki.certificateToAsn1(match[i])).getBytes();
2739 if(der1 === der2) {
2740 return true;
2741 }
2742 }
2743 return false;
2744 };
2745
2746 /**
2747 * Lists all of the certificates kept in the store.
2748 *
2749 * @return an array of all of the pki.certificate objects in the store.
2750 */
2751 caStore.listAllCertificates = function() {
2752 var certList = [];
2753
2754 for(var hash in caStore.certs) {
2755 if(caStore.certs.hasOwnProperty(hash)) {
2756 var value = caStore.certs[hash];
2757 if(!forge.util.isArray(value)) {
2758 certList.push(value);
2759 } else {
2760 for(var i = 0; i < value.length; ++i) {
2761 certList.push(value[i]);
2762 }
2763 }
2764 }
2765 }
2766
2767 return certList;
2768 };
2769
2770 /**
2771 * Removes a certificate from the store.
2772 *
2773 * @param cert the certificate to remove (either a pki.certificate or a
2774 * PEM-formatted certificate).
2775 *
2776 * @return the certificate that was removed or null if the certificate
2777 * wasn't in store.
2778 */
2779 caStore.removeCertificate = function(cert) {
2780 var result;
2781
2782 // convert from pem if necessary
2783 if(typeof cert === 'string') {
2784 cert = forge.pki.certificateFromPem(cert);
2785 }
2786 ensureSubjectHasHash(cert.subject);
2787 if(!caStore.hasCertificate(cert)) {
2788 return null;
2789 }
2790
2791 var match = getBySubject(cert.subject);
2792
2793 if(!forge.util.isArray(match)) {
2794 result = caStore.certs[cert.subject.hash];
2795 delete caStore.certs[cert.subject.hash];
2796 return result;
2797 }
2798
2799 // compare DER-encoding of certificates
2800 var der1 = asn1.toDer(pki.certificateToAsn1(cert)).getBytes();
2801 for(var i = 0; i < match.length; ++i) {
2802 var der2 = asn1.toDer(pki.certificateToAsn1(match[i])).getBytes();
2803 if(der1 === der2) {
2804 result = match[i];
2805 match.splice(i, 1);
2806 }
2807 }
2808 if(match.length === 0) {
2809 delete caStore.certs[cert.subject.hash];
2810 }
2811
2812 return result;
2813 };
2814
2815 function getBySubject(subject) {
2816 ensureSubjectHasHash(subject);
2817 return caStore.certs[subject.hash] || null;
2818 }
2819
2820 function ensureSubjectHasHash(subject) {
2821 // produce subject hash if it doesn't exist
2822 if(!subject.hash) {
2823 var md = forge.md.sha1.create();
2824 subject.attributes = pki.RDNAttributesAsArray(_dnToAsn1(subject), md);
2825 subject.hash = md.digest().toHex();
2826 }
2827 }
2828
2829 // auto-add passed in certs
2830 if(certs) {
2831 // parse PEM-formatted certificates as necessary
2832 for(var i = 0; i < certs.length; ++i) {
2833 var cert = certs[i];
2834 caStore.addCertificate(cert);
2835 }
2836 }
2837
2838 return caStore;
2839};
2840
2841/**
2842 * Certificate verification errors, based on TLS.
2843 */
2844pki.certificateError = {
2845 bad_certificate: 'forge.pki.BadCertificate',
2846 unsupported_certificate: 'forge.pki.UnsupportedCertificate',
2847 certificate_revoked: 'forge.pki.CertificateRevoked',
2848 certificate_expired: 'forge.pki.CertificateExpired',
2849 certificate_unknown: 'forge.pki.CertificateUnknown',
2850 unknown_ca: 'forge.pki.UnknownCertificateAuthority'
2851};
2852
2853/**
2854 * Verifies a certificate chain against the given Certificate Authority store
2855 * with an optional custom verify callback.
2856 *
2857 * @param caStore a certificate store to verify against.
2858 * @param chain the certificate chain to verify, with the root or highest
2859 * authority at the end (an array of certificates).
2860 * @param options a callback to be called for every certificate in the chain or
2861 * an object with:
2862 * verify a callback to be called for every certificate in the
2863 * chain
2864 * validityCheckDate the date against which the certificate
2865 * validity period should be checked. Pass null to not check
2866 * the validity period. By default, the current date is used.
2867 *
2868 * The verify callback has the following signature:
2869 *
2870 * verified - Set to true if certificate was verified, otherwise the
2871 * pki.certificateError for why the certificate failed.
2872 * depth - The current index in the chain, where 0 is the end point's cert.
2873 * certs - The certificate chain, *NOTE* an empty chain indicates an anonymous
2874 * end point.
2875 *
2876 * The function returns true on success and on failure either the appropriate
2877 * pki.certificateError or an object with 'error' set to the appropriate
2878 * pki.certificateError and 'message' set to a custom error message.
2879 *
2880 * @return true if successful, error thrown if not.
2881 */
2882pki.verifyCertificateChain = function(caStore, chain, options) {
2883 /* From: RFC3280 - Internet X.509 Public Key Infrastructure Certificate
2884 Section 6: Certification Path Validation
2885 See inline parentheticals related to this particular implementation.
2886
2887 The primary goal of path validation is to verify the binding between
2888 a subject distinguished name or a subject alternative name and subject
2889 public key, as represented in the end entity certificate, based on the
2890 public key of the trust anchor. This requires obtaining a sequence of
2891 certificates that support that binding. That sequence should be provided
2892 in the passed 'chain'. The trust anchor should be in the given CA
2893 store. The 'end entity' certificate is the certificate provided by the
2894 end point (typically a server) and is the first in the chain.
2895
2896 To meet this goal, the path validation process verifies, among other
2897 things, that a prospective certification path (a sequence of n
2898 certificates or a 'chain') satisfies the following conditions:
2899
2900 (a) for all x in {1, ..., n-1}, the subject of certificate x is
2901 the issuer of certificate x+1;
2902
2903 (b) certificate 1 is issued by the trust anchor;
2904
2905 (c) certificate n is the certificate to be validated; and
2906
2907 (d) for all x in {1, ..., n}, the certificate was valid at the
2908 time in question.
2909
2910 Note that here 'n' is index 0 in the chain and 1 is the last certificate
2911 in the chain and it must be signed by a certificate in the connection's
2912 CA store.
2913
2914 The path validation process also determines the set of certificate
2915 policies that are valid for this path, based on the certificate policies
2916 extension, policy mapping extension, policy constraints extension, and
2917 inhibit any-policy extension.
2918
2919 Note: Policy mapping extension not supported (Not Required).
2920
2921 Note: If the certificate has an unsupported critical extension, then it
2922 must be rejected.
2923
2924 Note: A certificate is self-issued if the DNs that appear in the subject
2925 and issuer fields are identical and are not empty.
2926
2927 The path validation algorithm assumes the following seven inputs are
2928 provided to the path processing logic. What this specific implementation
2929 will use is provided parenthetically:
2930
2931 (a) a prospective certification path of length n (the 'chain')
2932 (b) the current date/time: ('now').
2933 (c) user-initial-policy-set: A set of certificate policy identifiers
2934 naming the policies that are acceptable to the certificate user.
2935 The user-initial-policy-set contains the special value any-policy
2936 if the user is not concerned about certificate policy
2937 (Not implemented. Any policy is accepted).
2938 (d) trust anchor information, describing a CA that serves as a trust
2939 anchor for the certification path. The trust anchor information
2940 includes:
2941
2942 (1) the trusted issuer name,
2943 (2) the trusted public key algorithm,
2944 (3) the trusted public key, and
2945 (4) optionally, the trusted public key parameters associated
2946 with the public key.
2947
2948 (Trust anchors are provided via certificates in the CA store).
2949
2950 The trust anchor information may be provided to the path processing
2951 procedure in the form of a self-signed certificate. The trusted anchor
2952 information is trusted because it was delivered to the path processing
2953 procedure by some trustworthy out-of-band procedure. If the trusted
2954 public key algorithm requires parameters, then the parameters are
2955 provided along with the trusted public key (No parameters used in this
2956 implementation).
2957
2958 (e) initial-policy-mapping-inhibit, which indicates if policy mapping is
2959 allowed in the certification path.
2960 (Not implemented, no policy checking)
2961
2962 (f) initial-explicit-policy, which indicates if the path must be valid
2963 for at least one of the certificate policies in the user-initial-
2964 policy-set.
2965 (Not implemented, no policy checking)
2966
2967 (g) initial-any-policy-inhibit, which indicates whether the
2968 anyPolicy OID should be processed if it is included in a
2969 certificate.
2970 (Not implemented, so any policy is valid provided that it is
2971 not marked as critical) */
2972
2973 /* Basic Path Processing:
2974
2975 For each certificate in the 'chain', the following is checked:
2976
2977 1. The certificate validity period includes the current time.
2978 2. The certificate was signed by its parent (where the parent is either
2979 the next in the chain or from the CA store). Allow processing to
2980 continue to the next step if no parent is found but the certificate is
2981 in the CA store.
2982 3. TODO: The certificate has not been revoked.
2983 4. The certificate issuer name matches the parent's subject name.
2984 5. TODO: If the certificate is self-issued and not the final certificate
2985 in the chain, skip this step, otherwise verify that the subject name
2986 is within one of the permitted subtrees of X.500 distinguished names
2987 and that each of the alternative names in the subjectAltName extension
2988 (critical or non-critical) is within one of the permitted subtrees for
2989 that name type.
2990 6. TODO: If the certificate is self-issued and not the final certificate
2991 in the chain, skip this step, otherwise verify that the subject name
2992 is not within one of the excluded subtrees for X.500 distinguished
2993 names and none of the subjectAltName extension names are excluded for
2994 that name type.
2995 7. The other steps in the algorithm for basic path processing involve
2996 handling the policy extension which is not presently supported in this
2997 implementation. Instead, if a critical policy extension is found, the
2998 certificate is rejected as not supported.
2999 8. If the certificate is not the first or if its the only certificate in
3000 the chain (having no parent from the CA store or is self-signed) and it
3001 has a critical key usage extension, verify that the keyCertSign bit is
3002 set. If the key usage extension exists, verify that the basic
3003 constraints extension exists. If the basic constraints extension exists,
3004 verify that the cA flag is set. If pathLenConstraint is set, ensure that
3005 the number of certificates that precede in the chain (come earlier
3006 in the chain as implemented below), excluding the very first in the
3007 chain (typically the end-entity one), isn't greater than the
3008 pathLenConstraint. This constraint limits the number of intermediate
3009 CAs that may appear below a CA before only end-entity certificates
3010 may be issued. */
3011
3012 // if a verify callback is passed as the third parameter, package it within
3013 // the options object. This is to support a legacy function signature that
3014 // expected the verify callback as the third parameter.
3015 if(typeof options === 'function') {
3016 options = {verify: options};
3017 }
3018 options = options || {};
3019
3020 // copy cert chain references to another array to protect against changes
3021 // in verify callback
3022 chain = chain.slice(0);
3023 var certs = chain.slice(0);
3024
3025 var validityCheckDate = options.validityCheckDate;
3026 // if no validityCheckDate is specified, default to the current date. Make
3027 // sure to maintain the value null because it indicates that the validity
3028 // period should not be checked.
3029 if(typeof validityCheckDate === 'undefined') {
3030 validityCheckDate = new Date();
3031 }
3032
3033 // verify each cert in the chain using its parent, where the parent
3034 // is either the next in the chain or from the CA store
3035 var first = true;
3036 var error = null;
3037 var depth = 0;
3038 do {
3039 var cert = chain.shift();
3040 var parent = null;
3041 var selfSigned = false;
3042
3043 if(validityCheckDate) {
3044 // 1. check valid time
3045 if(validityCheckDate < cert.validity.notBefore ||
3046 validityCheckDate > cert.validity.notAfter) {
3047 error = {
3048 message: 'Certificate is not valid yet or has expired.',
3049 error: pki.certificateError.certificate_expired,
3050 notBefore: cert.validity.notBefore,
3051 notAfter: cert.validity.notAfter,
3052 // TODO: we might want to reconsider renaming 'now' to
3053 // 'validityCheckDate' should this API be changed in the future.
3054 now: validityCheckDate
3055 };
3056 }
3057 }
3058
3059 // 2. verify with parent from chain or CA store
3060 if(error === null) {
3061 parent = chain[0] || caStore.getIssuer(cert);
3062 if(parent === null) {
3063 // check for self-signed cert
3064 if(cert.isIssuer(cert)) {
3065 selfSigned = true;
3066 parent = cert;
3067 }
3068 }
3069
3070 if(parent) {
3071 // FIXME: current CA store implementation might have multiple
3072 // certificates where the issuer can't be determined from the
3073 // certificate (happens rarely with, eg: old certificates) so normalize
3074 // by always putting parents into an array
3075 // TODO: there's may be an extreme degenerate case currently uncovered
3076 // where an old intermediate certificate seems to have a matching parent
3077 // but none of the parents actually verify ... but the intermediate
3078 // is in the CA and it should pass this check; needs investigation
3079 var parents = parent;
3080 if(!forge.util.isArray(parents)) {
3081 parents = [parents];
3082 }
3083
3084 // try to verify with each possible parent (typically only one)
3085 var verified = false;
3086 while(!verified && parents.length > 0) {
3087 parent = parents.shift();
3088 try {
3089 verified = parent.verify(cert);
3090 } catch(ex) {
3091 // failure to verify, don't care why, try next one
3092 }
3093 }
3094
3095 if(!verified) {
3096 error = {
3097 message: 'Certificate signature is invalid.',
3098 error: pki.certificateError.bad_certificate
3099 };
3100 }
3101 }
3102
3103 if(error === null && (!parent || selfSigned) &&
3104 !caStore.hasCertificate(cert)) {
3105 // no parent issuer and certificate itself is not trusted
3106 error = {
3107 message: 'Certificate is not trusted.',
3108 error: pki.certificateError.unknown_ca
3109 };
3110 }
3111 }
3112
3113 // TODO: 3. check revoked
3114
3115 // 4. check for matching issuer/subject
3116 if(error === null && parent && !cert.isIssuer(parent)) {
3117 // parent is not issuer
3118 error = {
3119 message: 'Certificate issuer is invalid.',
3120 error: pki.certificateError.bad_certificate
3121 };
3122 }
3123
3124 // 5. TODO: check names with permitted names tree
3125
3126 // 6. TODO: check names against excluded names tree
3127
3128 // 7. check for unsupported critical extensions
3129 if(error === null) {
3130 // supported extensions
3131 var se = {
3132 keyUsage: true,
3133 basicConstraints: true
3134 };
3135 for(var i = 0; error === null && i < cert.extensions.length; ++i) {
3136 var ext = cert.extensions[i];
3137 if(ext.critical && !(ext.name in se)) {
3138 error = {
3139 message:
3140 'Certificate has an unsupported critical extension.',
3141 error: pki.certificateError.unsupported_certificate
3142 };
3143 }
3144 }
3145 }
3146
3147 // 8. check for CA if cert is not first or is the only certificate
3148 // remaining in chain with no parent or is self-signed
3149 if(error === null &&
3150 (!first || (chain.length === 0 && (!parent || selfSigned)))) {
3151 // first check keyUsage extension and then basic constraints
3152 var bcExt = cert.getExtension('basicConstraints');
3153 var keyUsageExt = cert.getExtension('keyUsage');
3154 if(keyUsageExt !== null) {
3155 // keyCertSign must be true and there must be a basic
3156 // constraints extension
3157 if(!keyUsageExt.keyCertSign || bcExt === null) {
3158 // bad certificate
3159 error = {
3160 message:
3161 'Certificate keyUsage or basicConstraints conflict ' +
3162 'or indicate that the certificate is not a CA. ' +
3163 'If the certificate is the only one in the chain or ' +
3164 'isn\'t the first then the certificate must be a ' +
3165 'valid CA.',
3166 error: pki.certificateError.bad_certificate
3167 };
3168 }
3169 }
3170 // check for absent basicConstraints on non-leaf certificates
3171 if(error === null && bcExt === null) {
3172 error = {
3173 message:
3174 'Certificate is missing basicConstraints extension and cannot ' +
3175 'be used as a CA.',
3176 error: pki.certificateError.bad_certificate
3177 };
3178 }
3179 // basic constraints cA flag must be set
3180 if(error === null && bcExt !== null && !bcExt.cA) {
3181 // bad certificate
3182 error = {
3183 message:
3184 'Certificate basicConstraints indicates the certificate ' +
3185 'is not a CA.',
3186 error: pki.certificateError.bad_certificate
3187 };
3188 }
3189 // if error is not null and keyUsage is available, then we know it
3190 // has keyCertSign and there is a basic constraints extension too,
3191 // which means we can check pathLenConstraint (if it exists)
3192 if(error === null && keyUsageExt !== null &&
3193 'pathLenConstraint' in bcExt) {
3194 // pathLen is the maximum # of intermediate CA certs that can be
3195 // found between the current certificate and the end-entity (depth 0)
3196 // certificate; this number does not include the end-entity (depth 0,
3197 // last in the chain) even if it happens to be a CA certificate itself
3198 var pathLen = depth - 1;
3199 if(pathLen > bcExt.pathLenConstraint) {
3200 // pathLenConstraint violated, bad certificate
3201 error = {
3202 message:
3203 'Certificate basicConstraints pathLenConstraint violated.',
3204 error: pki.certificateError.bad_certificate
3205 };
3206 }
3207 }
3208 }
3209
3210 // call application callback
3211 var vfd = (error === null) ? true : error.error;
3212 var ret = options.verify ? options.verify(vfd, depth, certs) : vfd;
3213 if(ret === true) {
3214 // clear any set error
3215 error = null;
3216 } else {
3217 // if passed basic tests, set default message and alert
3218 if(vfd === true) {
3219 error = {
3220 message: 'The application rejected the certificate.',
3221 error: pki.certificateError.bad_certificate
3222 };
3223 }
3224
3225 // check for custom error info
3226 if(ret || ret === 0) {
3227 // set custom message and error
3228 if(typeof ret === 'object' && !forge.util.isArray(ret)) {
3229 if(ret.message) {
3230 error.message = ret.message;
3231 }
3232 if(ret.error) {
3233 error.error = ret.error;
3234 }
3235 } else if(typeof ret === 'string') {
3236 // set custom error
3237 error.error = ret;
3238 }
3239 }
3240
3241 // throw error
3242 throw error;
3243 }
3244
3245 // no longer first cert in chain
3246 first = false;
3247 ++depth;
3248 } while(chain.length > 0);
3249
3250 return true;
3251};
Note: See TracBrowser for help on using the repository browser.