Passed
Push — master ( 445067...6ce435 )
by Johan
02:18
created

node_modules/node-forge/lib/x509.js   F

Complexity

Total Complexity 331
Complexity/F 4.66

Size

Lines of Code 3224
Function Count 71

Duplication

Duplicated Lines 127
Ratio 3.94 %

Importance

Changes 0
Metric Value
wmc 331
eloc 1651
mnd 260
bc 260
fnc 71
dl 127
loc 3224
rs 0.8
bpm 3.6619
cpm 4.6619
noi 2
c 0
b 0
f 0

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like node_modules/node-forge/lib/x509.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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
 */
110
var forge = require('./forge');
111
require('./aes');
112
require('./asn1');
113
require('./des');
114
require('./md');
115
require('./mgf');
116
require('./oids');
117
require('./pem');
118
require('./pss');
119
require('./rsa');
120
require('./util');
121
122
// shortcut for asn.1 API
123
var asn1 = forge.asn1;
124
125
/* Public Key Infrastructure (PKI) implementation. */
126
var pki = module.exports = forge.pki = forge.pki || {};
127
var oids = pki.oids;
128
129
// short name OID mappings
130
var _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
148
var publicKeyValidator = forge.pki.rsa.publicKeyValidator;
149
150
// validator for an X.509v3 certificate
151
var 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
324
var 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
409
var 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
459
var 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
 */
503
pki.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
 */
545
pki.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
 */
594
function _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
 */
643
var _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
 */
707
pki.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
 */
738
pki.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
 */
754
pki.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
 */
781
pki.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
 */
798
pki.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
 */
821
pki.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
 */
871
pki.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
 */
899
pki.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
 */
913
pki.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
 */
1275
pki.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
 */
1471
pki.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
 */
1491
pki.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
 */
1648
pki.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
 */
1754
pki.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
 */
1951
function _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
 */
2000
function _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
 */
2029
function _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
 */
2091
function _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
 */
2386
function _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
 */
2437
function _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
2485
var jan_1_1950 = new Date('1950-01-01T00:00:00Z');
2486
var 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
 */
2496
function _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
 */
2515
pki.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
 */
2592
pki.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
 */
2616
pki.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
 */
2627
pki.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
 */
2656
pki.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
 */
2678
pki.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
 */
2715
pki.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
 */
2746
pki.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
 */
2935
pki.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
 */
2973
pki.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
};
3334