source: trip-planner-front/node_modules/node-forge/lib/x509.js@ 571e0df

Last change on this file since 571e0df was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

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