| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333 | 
							- /**
 
-  * Javascript implementation of X.509 and related components (such as
 
-  * Certification Signing Requests) of a Public Key Infrastructure.
 
-  *
 
-  * @author Dave Longley
 
-  *
 
-  * Copyright (c) 2010-2014 Digital Bazaar, Inc.
 
-  *
 
-  * The ASN.1 representation of an X.509v3 certificate is as follows
 
-  * (see RFC 2459):
 
-  *
 
-  * Certificate ::= SEQUENCE {
 
-  *   tbsCertificate       TBSCertificate,
 
-  *   signatureAlgorithm   AlgorithmIdentifier,
 
-  *   signatureValue       BIT STRING
 
-  * }
 
-  *
 
-  * TBSCertificate ::= SEQUENCE {
 
-  *   version         [0]  EXPLICIT Version DEFAULT v1,
 
-  *   serialNumber         CertificateSerialNumber,
 
-  *   signature            AlgorithmIdentifier,
 
-  *   issuer               Name,
 
-  *   validity             Validity,
 
-  *   subject              Name,
 
-  *   subjectPublicKeyInfo SubjectPublicKeyInfo,
 
-  *   issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
 
-  *                        -- If present, version shall be v2 or v3
 
-  *   subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
 
-  *                        -- If present, version shall be v2 or v3
 
-  *   extensions      [3]  EXPLICIT Extensions OPTIONAL
 
-  *                        -- If present, version shall be v3
 
-  * }
 
-  *
 
-  * Version ::= INTEGER  { v1(0), v2(1), v3(2) }
 
-  *
 
-  * CertificateSerialNumber ::= INTEGER
 
-  *
 
-  * Name ::= CHOICE {
 
-  *   // only one possible choice for now
 
-  *   RDNSequence
 
-  * }
 
-  *
 
-  * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
 
-  *
 
-  * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
 
-  *
 
-  * AttributeTypeAndValue ::= SEQUENCE {
 
-  *   type     AttributeType,
 
-  *   value    AttributeValue
 
-  * }
 
-  * AttributeType ::= OBJECT IDENTIFIER
 
-  * AttributeValue ::= ANY DEFINED BY AttributeType
 
-  *
 
-  * Validity ::= SEQUENCE {
 
-  *   notBefore      Time,
 
-  *   notAfter       Time
 
-  * }
 
-  *
 
-  * Time ::= CHOICE {
 
-  *   utcTime        UTCTime,
 
-  *   generalTime    GeneralizedTime
 
-  * }
 
-  *
 
-  * UniqueIdentifier ::= BIT STRING
 
-  *
 
-  * SubjectPublicKeyInfo ::= SEQUENCE {
 
-  *   algorithm            AlgorithmIdentifier,
 
-  *   subjectPublicKey     BIT STRING
 
-  * }
 
-  *
 
-  * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
 
-  *
 
-  * Extension ::= SEQUENCE {
 
-  *   extnID      OBJECT IDENTIFIER,
 
-  *   critical    BOOLEAN DEFAULT FALSE,
 
-  *   extnValue   OCTET STRING
 
-  * }
 
-  *
 
-  * The only key algorithm currently supported for PKI is RSA.
 
-  *
 
-  * RSASSA-PSS signatures are described in RFC 3447 and RFC 4055.
 
-  *
 
-  * PKCS#10 v1.7 describes certificate signing requests:
 
-  *
 
-  * CertificationRequestInfo:
 
-  *
 
-  * CertificationRequestInfo ::= SEQUENCE {
 
-  *   version       INTEGER { v1(0) } (v1,...),
 
-  *   subject       Name,
 
-  *   subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
 
-  *   attributes    [0] Attributes{{ CRIAttributes }}
 
-  * }
 
-  *
 
-  * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
 
-  *
 
-  * CRIAttributes  ATTRIBUTE  ::= {
 
-  *   ... -- add any locally defined attributes here -- }
 
-  *
 
-  * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
 
-  *   type   ATTRIBUTE.&id({IOSet}),
 
-  *   values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})
 
-  * }
 
-  *
 
-  * CertificationRequest ::= SEQUENCE {
 
-  *   certificationRequestInfo CertificationRequestInfo,
 
-  *   signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
 
-  *   signature          BIT STRING
 
-  * }
 
-  */
 
- var forge = require('./forge');
 
- require('./aes');
 
- require('./asn1');
 
- require('./des');
 
- require('./md');
 
- require('./mgf');
 
- require('./oids');
 
- require('./pem');
 
- require('./pss');
 
- require('./rsa');
 
- require('./util');
 
- // shortcut for asn.1 API
 
- var asn1 = forge.asn1;
 
- /* Public Key Infrastructure (PKI) implementation. */
 
- var pki = module.exports = forge.pki = forge.pki || {};
 
- var oids = pki.oids;
 
- // short name OID mappings
 
- var _shortNames = {};
 
- _shortNames['CN'] = oids['commonName'];
 
- _shortNames['commonName'] = 'CN';
 
- _shortNames['C'] = oids['countryName'];
 
- _shortNames['countryName'] = 'C';
 
- _shortNames['L'] = oids['localityName'];
 
- _shortNames['localityName'] = 'L';
 
- _shortNames['ST'] = oids['stateOrProvinceName'];
 
- _shortNames['stateOrProvinceName'] = 'ST';
 
- _shortNames['O'] = oids['organizationName'];
 
- _shortNames['organizationName'] = 'O';
 
- _shortNames['OU'] = oids['organizationalUnitName'];
 
- _shortNames['organizationalUnitName'] = 'OU';
 
- _shortNames['E'] = oids['emailAddress'];
 
- _shortNames['emailAddress'] = 'E';
 
- // validator for an SubjectPublicKeyInfo structure
 
- // Note: Currently only works with an RSA public key
 
- var publicKeyValidator = forge.pki.rsa.publicKeyValidator;
 
- // validator for an X.509v3 certificate
 
- var x509CertificateValidator = {
 
-   name: 'Certificate',
 
-   tagClass: asn1.Class.UNIVERSAL,
 
-   type: asn1.Type.SEQUENCE,
 
-   constructed: true,
 
-   value: [{
 
-     name: 'Certificate.TBSCertificate',
 
-     tagClass: asn1.Class.UNIVERSAL,
 
-     type: asn1.Type.SEQUENCE,
 
-     constructed: true,
 
-     captureAsn1: 'tbsCertificate',
 
-     value: [{
 
-       name: 'Certificate.TBSCertificate.version',
 
-       tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-       type: 0,
 
-       constructed: true,
 
-       optional: true,
 
-       value: [{
 
-         name: 'Certificate.TBSCertificate.version.integer',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.INTEGER,
 
-         constructed: false,
 
-         capture: 'certVersion'
 
-       }]
 
-     }, {
 
-       name: 'Certificate.TBSCertificate.serialNumber',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.INTEGER,
 
-       constructed: false,
 
-       capture: 'certSerialNumber'
 
-     }, {
 
-       name: 'Certificate.TBSCertificate.signature',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.SEQUENCE,
 
-       constructed: true,
 
-       value: [{
 
-         name: 'Certificate.TBSCertificate.signature.algorithm',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.OID,
 
-         constructed: false,
 
-         capture: 'certinfoSignatureOid'
 
-       }, {
 
-         name: 'Certificate.TBSCertificate.signature.parameters',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         optional: true,
 
-         captureAsn1: 'certinfoSignatureParams'
 
-       }]
 
-     }, {
 
-       name: 'Certificate.TBSCertificate.issuer',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.SEQUENCE,
 
-       constructed: true,
 
-       captureAsn1: 'certIssuer'
 
-     }, {
 
-       name: 'Certificate.TBSCertificate.validity',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.SEQUENCE,
 
-       constructed: true,
 
-       // Note: UTC and generalized times may both appear so the capture
 
-       // names are based on their detected order, the names used below
 
-       // are only for the common case, which validity time really means
 
-       // "notBefore" and which means "notAfter" will be determined by order
 
-       value: [{
 
-         // notBefore (Time) (UTC time case)
 
-         name: 'Certificate.TBSCertificate.validity.notBefore (utc)',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.UTCTIME,
 
-         constructed: false,
 
-         optional: true,
 
-         capture: 'certValidity1UTCTime'
 
-       }, {
 
-         // notBefore (Time) (generalized time case)
 
-         name: 'Certificate.TBSCertificate.validity.notBefore (generalized)',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.GENERALIZEDTIME,
 
-         constructed: false,
 
-         optional: true,
 
-         capture: 'certValidity2GeneralizedTime'
 
-       }, {
 
-         // notAfter (Time) (only UTC time is supported)
 
-         name: 'Certificate.TBSCertificate.validity.notAfter (utc)',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.UTCTIME,
 
-         constructed: false,
 
-         optional: true,
 
-         capture: 'certValidity3UTCTime'
 
-       }, {
 
-         // notAfter (Time) (only UTC time is supported)
 
-         name: 'Certificate.TBSCertificate.validity.notAfter (generalized)',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.GENERALIZEDTIME,
 
-         constructed: false,
 
-         optional: true,
 
-         capture: 'certValidity4GeneralizedTime'
 
-       }]
 
-     }, {
 
-       // Name (subject) (RDNSequence)
 
-       name: 'Certificate.TBSCertificate.subject',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.SEQUENCE,
 
-       constructed: true,
 
-       captureAsn1: 'certSubject'
 
-     },
 
-     // SubjectPublicKeyInfo
 
-     publicKeyValidator,
 
-     {
 
-       // issuerUniqueID (optional)
 
-       name: 'Certificate.TBSCertificate.issuerUniqueID',
 
-       tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-       type: 1,
 
-       constructed: true,
 
-       optional: true,
 
-       value: [{
 
-         name: 'Certificate.TBSCertificate.issuerUniqueID.id',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.BITSTRING,
 
-         constructed: false,
 
-         // TODO: support arbitrary bit length ids
 
-         captureBitStringValue: 'certIssuerUniqueId'
 
-       }]
 
-     }, {
 
-       // subjectUniqueID (optional)
 
-       name: 'Certificate.TBSCertificate.subjectUniqueID',
 
-       tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-       type: 2,
 
-       constructed: true,
 
-       optional: true,
 
-       value: [{
 
-         name: 'Certificate.TBSCertificate.subjectUniqueID.id',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.BITSTRING,
 
-         constructed: false,
 
-         // TODO: support arbitrary bit length ids
 
-         captureBitStringValue: 'certSubjectUniqueId'
 
-       }]
 
-     }, {
 
-       // Extensions (optional)
 
-       name: 'Certificate.TBSCertificate.extensions',
 
-       tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-       type: 3,
 
-       constructed: true,
 
-       captureAsn1: 'certExtensions',
 
-       optional: true
 
-     }]
 
-   }, {
 
-     // AlgorithmIdentifier (signature algorithm)
 
-     name: 'Certificate.signatureAlgorithm',
 
-     tagClass: asn1.Class.UNIVERSAL,
 
-     type: asn1.Type.SEQUENCE,
 
-     constructed: true,
 
-     value: [{
 
-       // algorithm
 
-       name: 'Certificate.signatureAlgorithm.algorithm',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.OID,
 
-       constructed: false,
 
-       capture: 'certSignatureOid'
 
-     }, {
 
-       name: 'Certificate.TBSCertificate.signature.parameters',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       optional: true,
 
-       captureAsn1: 'certSignatureParams'
 
-     }]
 
-   }, {
 
-     // SignatureValue
 
-     name: 'Certificate.signatureValue',
 
-     tagClass: asn1.Class.UNIVERSAL,
 
-     type: asn1.Type.BITSTRING,
 
-     constructed: false,
 
-     captureBitStringValue: 'certSignature'
 
-   }]
 
- };
 
- var rsassaPssParameterValidator = {
 
-   name: 'rsapss',
 
-   tagClass: asn1.Class.UNIVERSAL,
 
-   type: asn1.Type.SEQUENCE,
 
-   constructed: true,
 
-   value: [{
 
-     name: 'rsapss.hashAlgorithm',
 
-     tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-     type: 0,
 
-     constructed: true,
 
-     value: [{
 
-       name: 'rsapss.hashAlgorithm.AlgorithmIdentifier',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Class.SEQUENCE,
 
-       constructed: true,
 
-       optional: true,
 
-       value: [{
 
-         name: 'rsapss.hashAlgorithm.AlgorithmIdentifier.algorithm',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.OID,
 
-         constructed: false,
 
-         capture: 'hashOid'
 
-         /* parameter block omitted, for SHA1 NULL anyhow. */
 
-       }]
 
-     }]
 
-   }, {
 
-     name: 'rsapss.maskGenAlgorithm',
 
-     tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-     type: 1,
 
-     constructed: true,
 
-     value: [{
 
-       name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Class.SEQUENCE,
 
-       constructed: true,
 
-       optional: true,
 
-       value: [{
 
-         name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.algorithm',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.OID,
 
-         constructed: false,
 
-         capture: 'maskGenOid'
 
-       }, {
 
-         name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.SEQUENCE,
 
-         constructed: true,
 
-         value: [{
 
-           name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params.algorithm',
 
-           tagClass: asn1.Class.UNIVERSAL,
 
-           type: asn1.Type.OID,
 
-           constructed: false,
 
-           capture: 'maskGenHashOid'
 
-           /* parameter block omitted, for SHA1 NULL anyhow. */
 
-         }]
 
-       }]
 
-     }]
 
-   }, {
 
-     name: 'rsapss.saltLength',
 
-     tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-     type: 2,
 
-     optional: true,
 
-     value: [{
 
-       name: 'rsapss.saltLength.saltLength',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Class.INTEGER,
 
-       constructed: false,
 
-       capture: 'saltLength'
 
-     }]
 
-   }, {
 
-     name: 'rsapss.trailerField',
 
-     tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-     type: 3,
 
-     optional: true,
 
-     value: [{
 
-       name: 'rsapss.trailer.trailer',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Class.INTEGER,
 
-       constructed: false,
 
-       capture: 'trailer'
 
-     }]
 
-   }]
 
- };
 
- // validator for a CertificationRequestInfo structure
 
- var certificationRequestInfoValidator = {
 
-   name: 'CertificationRequestInfo',
 
-   tagClass: asn1.Class.UNIVERSAL,
 
-   type: asn1.Type.SEQUENCE,
 
-   constructed: true,
 
-   captureAsn1: 'certificationRequestInfo',
 
-   value: [{
 
-     name: 'CertificationRequestInfo.integer',
 
-     tagClass: asn1.Class.UNIVERSAL,
 
-     type: asn1.Type.INTEGER,
 
-     constructed: false,
 
-     capture: 'certificationRequestInfoVersion'
 
-   }, {
 
-     // Name (subject) (RDNSequence)
 
-     name: 'CertificationRequestInfo.subject',
 
-     tagClass: asn1.Class.UNIVERSAL,
 
-     type: asn1.Type.SEQUENCE,
 
-     constructed: true,
 
-     captureAsn1: 'certificationRequestInfoSubject'
 
-   },
 
-   // SubjectPublicKeyInfo
 
-   publicKeyValidator,
 
-   {
 
-     name: 'CertificationRequestInfo.attributes',
 
-     tagClass: asn1.Class.CONTEXT_SPECIFIC,
 
-     type: 0,
 
-     constructed: true,
 
-     optional: true,
 
-     capture: 'certificationRequestInfoAttributes',
 
-     value: [{
 
-       name: 'CertificationRequestInfo.attributes',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.SEQUENCE,
 
-       constructed: true,
 
-       value: [{
 
-         name: 'CertificationRequestInfo.attributes.type',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.OID,
 
-         constructed: false
 
-       }, {
 
-         name: 'CertificationRequestInfo.attributes.value',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.SET,
 
-         constructed: true
 
-       }]
 
-     }]
 
-   }]
 
- };
 
- // validator for a CertificationRequest structure
 
- var certificationRequestValidator = {
 
-   name: 'CertificationRequest',
 
-   tagClass: asn1.Class.UNIVERSAL,
 
-   type: asn1.Type.SEQUENCE,
 
-   constructed: true,
 
-   captureAsn1: 'csr',
 
-   value: [
 
-     certificationRequestInfoValidator, {
 
-       // AlgorithmIdentifier (signature algorithm)
 
-       name: 'CertificationRequest.signatureAlgorithm',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.SEQUENCE,
 
-       constructed: true,
 
-       value: [{
 
-         // algorithm
 
-         name: 'CertificationRequest.signatureAlgorithm.algorithm',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         type: asn1.Type.OID,
 
-         constructed: false,
 
-         capture: 'csrSignatureOid'
 
-       }, {
 
-         name: 'CertificationRequest.signatureAlgorithm.parameters',
 
-         tagClass: asn1.Class.UNIVERSAL,
 
-         optional: true,
 
-         captureAsn1: 'csrSignatureParams'
 
-       }]
 
-     }, {
 
-       // signature
 
-       name: 'CertificationRequest.signature',
 
-       tagClass: asn1.Class.UNIVERSAL,
 
-       type: asn1.Type.BITSTRING,
 
-       constructed: false,
 
-       captureBitStringValue: 'csrSignature'
 
-     }
 
-   ]
 
- };
 
- /**
 
-  * Converts an RDNSequence of ASN.1 DER-encoded RelativeDistinguishedName
 
-  * sets into an array with objects that have type and value properties.
 
-  *
 
-  * @param rdn the RDNSequence to convert.
 
-  * @param md a message digest to append type and value to if provided.
 
-  */
 
- pki.RDNAttributesAsArray = function(rdn, md) {
 
-   var rval = [];
 
-   // each value in 'rdn' in is a SET of RelativeDistinguishedName
 
-   var set, attr, obj;
 
-   for(var si = 0; si < rdn.value.length; ++si) {
 
-     // get the RelativeDistinguishedName set
 
-     set = rdn.value[si];
 
-     // each value in the SET is an AttributeTypeAndValue sequence
 
-     // containing first a type (an OID) and second a value (defined by
 
-     // the OID)
 
-     for(var i = 0; i < set.value.length; ++i) {
 
-       obj = {};
 
-       attr = set.value[i];
 
-       obj.type = asn1.derToOid(attr.value[0].value);
 
-       obj.value = attr.value[1].value;
 
-       obj.valueTagClass = attr.value[1].type;
 
-       // if the OID is known, get its name and short name
 
-       if(obj.type in oids) {
 
-         obj.name = oids[obj.type];
 
-         if(obj.name in _shortNames) {
 
-           obj.shortName = _shortNames[obj.name];
 
-         }
 
-       }
 
-       if(md) {
 
-         md.update(obj.type);
 
-         md.update(obj.value);
 
-       }
 
-       rval.push(obj);
 
-     }
 
-   }
 
-   return rval;
 
- };
 
- /**
 
-  * Converts ASN.1 CRIAttributes into an array with objects that have type and
 
-  * value properties.
 
-  *
 
-  * @param attributes the CRIAttributes to convert.
 
-  */
 
- pki.CRIAttributesAsArray = function(attributes) {
 
-   var rval = [];
 
-   // each value in 'attributes' in is a SEQUENCE with an OID and a SET
 
-   for(var si = 0; si < attributes.length; ++si) {
 
-     // get the attribute sequence
 
-     var seq = attributes[si];
 
-     // each value in the SEQUENCE containing first a type (an OID) and
 
-     // second a set of values (defined by the OID)
 
-     var type = asn1.derToOid(seq.value[0].value);
 
-     var values = seq.value[1].value;
 
-     for(var vi = 0; vi < values.length; ++vi) {
 
-       var obj = {};
 
-       obj.type = type;
 
-       obj.value = values[vi].value;
 
-       obj.valueTagClass = values[vi].type;
 
-       // if the OID is known, get its name and short name
 
-       if(obj.type in oids) {
 
-         obj.name = oids[obj.type];
 
-         if(obj.name in _shortNames) {
 
-           obj.shortName = _shortNames[obj.name];
 
-         }
 
-       }
 
-       // parse extensions
 
-       if(obj.type === oids.extensionRequest) {
 
-         obj.extensions = [];
 
-         for(var ei = 0; ei < obj.value.length; ++ei) {
 
-           obj.extensions.push(pki.certificateExtensionFromAsn1(obj.value[ei]));
 
-         }
 
-       }
 
-       rval.push(obj);
 
-     }
 
-   }
 
-   return rval;
 
- };
 
- /**
 
-  * Gets an issuer or subject attribute from its name, type, or short name.
 
-  *
 
-  * @param obj the issuer or subject object.
 
-  * @param options a short name string or an object with:
 
-  *          shortName the short name for the attribute.
 
-  *          name the name for the attribute.
 
-  *          type the type for the attribute.
 
-  *
 
-  * @return the attribute.
 
-  */
 
- function _getAttribute(obj, options) {
 
-   if(typeof options === 'string') {
 
-     options = {shortName: options};
 
-   }
 
-   var rval = null;
 
-   var attr;
 
-   for(var i = 0; rval === null && i < obj.attributes.length; ++i) {
 
-     attr = obj.attributes[i];
 
-     if(options.type && options.type === attr.type) {
 
-       rval = attr;
 
-     } else if(options.name && options.name === attr.name) {
 
-       rval = attr;
 
-     } else if(options.shortName && options.shortName === attr.shortName) {
 
-       rval = attr;
 
-     }
 
-   }
 
-   return rval;
 
- }
 
- /**
 
-  * Converts signature parameters from ASN.1 structure.
 
-  *
 
-  * Currently only RSASSA-PSS supported.  The PKCS#1 v1.5 signature scheme had
 
-  * no parameters.
 
-  *
 
-  * RSASSA-PSS-params  ::=  SEQUENCE  {
 
-  *   hashAlgorithm      [0] HashAlgorithm DEFAULT
 
-  *                             sha1Identifier,
 
-  *   maskGenAlgorithm   [1] MaskGenAlgorithm DEFAULT
 
-  *                             mgf1SHA1Identifier,
 
-  *   saltLength         [2] INTEGER DEFAULT 20,
 
-  *   trailerField       [3] INTEGER DEFAULT 1
 
-  * }
 
-  *
 
-  * HashAlgorithm  ::=  AlgorithmIdentifier
 
-  *
 
-  * MaskGenAlgorithm  ::=  AlgorithmIdentifier
 
-  *
 
-  * AlgorithmIdentifer ::= SEQUENCE {
 
-  *   algorithm OBJECT IDENTIFIER,
 
-  *   parameters ANY DEFINED BY algorithm OPTIONAL
 
-  * }
 
-  *
 
-  * @param oid The OID specifying the signature algorithm
 
-  * @param obj The ASN.1 structure holding the parameters
 
-  * @param fillDefaults Whether to use return default values where omitted
 
-  * @return signature parameter object
 
-  */
 
- var _readSignatureParameters = function(oid, obj, fillDefaults) {
 
-   var params = {};
 
-   if(oid !== oids['RSASSA-PSS']) {
 
-     return params;
 
-   }
 
-   if(fillDefaults) {
 
-     params = {
 
-       hash: {
 
-         algorithmOid: oids['sha1']
 
-       },
 
-       mgf: {
 
-         algorithmOid: oids['mgf1'],
 
-         hash: {
 
-           algorithmOid: oids['sha1']
 
-         }
 
-       },
 
-       saltLength: 20
 
-     };
 
-   }
 
-   var capture = {};
 
-   var errors = [];
 
-   if(!asn1.validate(obj, rsassaPssParameterValidator, capture, errors)) {
 
-     var error = new Error('Cannot read RSASSA-PSS parameter block.');
 
-     error.errors = errors;
 
-     throw error;
 
-   }
 
-   if(capture.hashOid !== undefined) {
 
-     params.hash = params.hash || {};
 
-     params.hash.algorithmOid = asn1.derToOid(capture.hashOid);
 
-   }
 
-   if(capture.maskGenOid !== undefined) {
 
-     params.mgf = params.mgf || {};
 
-     params.mgf.algorithmOid = asn1.derToOid(capture.maskGenOid);
 
-     params.mgf.hash = params.mgf.hash || {};
 
-     params.mgf.hash.algorithmOid = asn1.derToOid(capture.maskGenHashOid);
 
-   }
 
-   if(capture.saltLength !== undefined) {
 
-     params.saltLength = capture.saltLength.charCodeAt(0);
 
-   }
 
-   return params;
 
- };
 
- /**
 
-  * Converts an X.509 certificate from PEM format.
 
-  *
 
-  * Note: If the certificate is to be verified then compute hash should
 
-  * be set to true. This will scan the TBSCertificate part of the ASN.1
 
-  * object while it is converted so it doesn't need to be converted back
 
-  * to ASN.1-DER-encoding later.
 
-  *
 
-  * @param pem the PEM-formatted certificate.
 
-  * @param computeHash true to compute the hash for verification.
 
-  * @param strict true to be strict when checking ASN.1 value lengths, false to
 
-  *          allow truncated values (default: true).
 
-  *
 
-  * @return the certificate.
 
-  */
 
- pki.certificateFromPem = function(pem, computeHash, strict) {
 
-   var msg = forge.pem.decode(pem)[0];
 
-   if(msg.type !== 'CERTIFICATE' &&
 
-     msg.type !== 'X509 CERTIFICATE' &&
 
-     msg.type !== 'TRUSTED CERTIFICATE') {
 
-     var error = new Error(
 
-       'Could not convert certificate from PEM; PEM header type ' +
 
-       'is not "CERTIFICATE", "X509 CERTIFICATE", or "TRUSTED CERTIFICATE".');
 
-     error.headerType = msg.type;
 
-     throw error;
 
-   }
 
-   if(msg.procType && msg.procType.type === 'ENCRYPTED') {
 
-     throw new Error(
 
-       'Could not convert certificate from PEM; PEM is encrypted.');
 
-   }
 
-   // convert DER to ASN.1 object
 
-   var obj = asn1.fromDer(msg.body, strict);
 
-   return pki.certificateFromAsn1(obj, computeHash);
 
- };
 
- /**
 
-  * Converts an X.509 certificate to PEM format.
 
-  *
 
-  * @param cert the certificate.
 
-  * @param maxline the maximum characters per line, defaults to 64.
 
-  *
 
-  * @return the PEM-formatted certificate.
 
-  */
 
- pki.certificateToPem = function(cert, maxline) {
 
-   // convert to ASN.1, then DER, then PEM-encode
 
-   var msg = {
 
-     type: 'CERTIFICATE',
 
-     body: asn1.toDer(pki.certificateToAsn1(cert)).getBytes()
 
-   };
 
-   return forge.pem.encode(msg, {maxline: maxline});
 
- };
 
- /**
 
-  * Converts an RSA public key from PEM format.
 
-  *
 
-  * @param pem the PEM-formatted public key.
 
-  *
 
-  * @return the public key.
 
-  */
 
- pki.publicKeyFromPem = function(pem) {
 
-   var msg = forge.pem.decode(pem)[0];
 
-   if(msg.type !== 'PUBLIC KEY' && msg.type !== 'RSA PUBLIC KEY') {
 
-     var error = new Error('Could not convert public key from PEM; PEM header ' +
 
-       'type is not "PUBLIC KEY" or "RSA PUBLIC KEY".');
 
-     error.headerType = msg.type;
 
-     throw error;
 
-   }
 
-   if(msg.procType && msg.procType.type === 'ENCRYPTED') {
 
-     throw new Error('Could not convert public key from PEM; PEM is encrypted.');
 
-   }
 
-   // convert DER to ASN.1 object
 
-   var obj = asn1.fromDer(msg.body);
 
-   return pki.publicKeyFromAsn1(obj);
 
- };
 
- /**
 
-  * Converts an RSA public key to PEM format (using a SubjectPublicKeyInfo).
 
-  *
 
-  * @param key the public key.
 
-  * @param maxline the maximum characters per line, defaults to 64.
 
-  *
 
-  * @return the PEM-formatted public key.
 
-  */
 
- pki.publicKeyToPem = function(key, maxline) {
 
-   // convert to ASN.1, then DER, then PEM-encode
 
-   var msg = {
 
-     type: 'PUBLIC KEY',
 
-     body: asn1.toDer(pki.publicKeyToAsn1(key)).getBytes()
 
-   };
 
-   return forge.pem.encode(msg, {maxline: maxline});
 
- };
 
- /**
 
-  * Converts an RSA public key to PEM format (using an RSAPublicKey).
 
-  *
 
-  * @param key the public key.
 
-  * @param maxline the maximum characters per line, defaults to 64.
 
-  *
 
-  * @return the PEM-formatted public key.
 
-  */
 
- pki.publicKeyToRSAPublicKeyPem = function(key, maxline) {
 
-   // convert to ASN.1, then DER, then PEM-encode
 
-   var msg = {
 
-     type: 'RSA PUBLIC KEY',
 
-     body: asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes()
 
-   };
 
-   return forge.pem.encode(msg, {maxline: maxline});
 
- };
 
- /**
 
-  * Gets a fingerprint for the given public key.
 
-  *
 
-  * @param options the options to use.
 
-  *          [md] the message digest object to use (defaults to forge.md.sha1).
 
-  *          [type] the type of fingerprint, such as 'RSAPublicKey',
 
-  *            'SubjectPublicKeyInfo' (defaults to 'RSAPublicKey').
 
-  *          [encoding] an alternative output encoding, such as 'hex'
 
-  *            (defaults to none, outputs a byte buffer).
 
-  *          [delimiter] the delimiter to use between bytes for 'hex' encoded
 
-  *            output, eg: ':' (defaults to none).
 
-  *
 
-  * @return the fingerprint as a byte buffer or other encoding based on options.
 
-  */
 
- pki.getPublicKeyFingerprint = function(key, options) {
 
-   options = options || {};
 
-   var md = options.md || forge.md.sha1.create();
 
-   var type = options.type || 'RSAPublicKey';
 
-   var bytes;
 
-   switch(type) {
 
-     case 'RSAPublicKey':
 
-       bytes = asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes();
 
-       break;
 
-     case 'SubjectPublicKeyInfo':
 
-       bytes = asn1.toDer(pki.publicKeyToAsn1(key)).getBytes();
 
-       break;
 
-     default:
 
-       throw new Error('Unknown fingerprint type "' + options.type + '".');
 
-   }
 
-   // hash public key bytes
 
-   md.start();
 
-   md.update(bytes);
 
-   var digest = md.digest();
 
-   if(options.encoding === 'hex') {
 
-     var hex = digest.toHex();
 
-     if(options.delimiter) {
 
-       return hex.match(/.{2}/g).join(options.delimiter);
 
-     }
 
-     return hex;
 
-   } else if(options.encoding === 'binary') {
 
-     return digest.getBytes();
 
-   } else if(options.encoding) {
 
-     throw new Error('Unknown encoding "' + options.encoding + '".');
 
-   }
 
-   return digest;
 
- };
 
- /**
 
-  * Converts a PKCS#10 certification request (CSR) from PEM format.
 
-  *
 
-  * Note: If the certification request is to be verified then compute hash
 
-  * should be set to true. This will scan the CertificationRequestInfo part of
 
-  * the ASN.1 object while it is converted so it doesn't need to be converted
 
-  * back to ASN.1-DER-encoding later.
 
-  *
 
-  * @param pem the PEM-formatted certificate.
 
-  * @param computeHash true to compute the hash for verification.
 
-  * @param strict true to be strict when checking ASN.1 value lengths, false to
 
-  *          allow truncated values (default: true).
 
-  *
 
-  * @return the certification request (CSR).
 
-  */
 
- pki.certificationRequestFromPem = function(pem, computeHash, strict) {
 
-   var msg = forge.pem.decode(pem)[0];
 
-   if(msg.type !== 'CERTIFICATE REQUEST') {
 
-     var error = new Error('Could not convert certification request from PEM; ' +
 
-       'PEM header type is not "CERTIFICATE REQUEST".');
 
-     error.headerType = msg.type;
 
-     throw error;
 
-   }
 
-   if(msg.procType && msg.procType.type === 'ENCRYPTED') {
 
-     throw new Error('Could not convert certification request from PEM; ' +
 
-       'PEM is encrypted.');
 
-   }
 
-   // convert DER to ASN.1 object
 
-   var obj = asn1.fromDer(msg.body, strict);
 
-   return pki.certificationRequestFromAsn1(obj, computeHash);
 
- };
 
- /**
 
-  * Converts a PKCS#10 certification request (CSR) to PEM format.
 
-  *
 
-  * @param csr the certification request.
 
-  * @param maxline the maximum characters per line, defaults to 64.
 
-  *
 
-  * @return the PEM-formatted certification request.
 
-  */
 
- pki.certificationRequestToPem = function(csr, maxline) {
 
-   // convert to ASN.1, then DER, then PEM-encode
 
-   var msg = {
 
-     type: 'CERTIFICATE REQUEST',
 
-     body: asn1.toDer(pki.certificationRequestToAsn1(csr)).getBytes()
 
-   };
 
-   return forge.pem.encode(msg, {maxline: maxline});
 
- };
 
- /**
 
-  * Creates an empty X.509v3 RSA certificate.
 
-  *
 
-  * @return the certificate.
 
-  */
 
- pki.createCertificate = function() {
 
-   var cert = {};
 
-   cert.version = 0x02;
 
-   cert.serialNumber = '00';
 
-   cert.signatureOid = null;
 
-   cert.signature = null;
 
-   cert.siginfo = {};
 
-   cert.siginfo.algorithmOid = null;
 
-   cert.validity = {};
 
-   cert.validity.notBefore = new Date();
 
-   cert.validity.notAfter = new Date();
 
-   cert.issuer = {};
 
-   cert.issuer.getField = function(sn) {
 
-     return _getAttribute(cert.issuer, sn);
 
-   };
 
-   cert.issuer.addField = function(attr) {
 
-     _fillMissingFields([attr]);
 
-     cert.issuer.attributes.push(attr);
 
-   };
 
-   cert.issuer.attributes = [];
 
-   cert.issuer.hash = null;
 
-   cert.subject = {};
 
-   cert.subject.getField = function(sn) {
 
-     return _getAttribute(cert.subject, sn);
 
-   };
 
-   cert.subject.addField = function(attr) {
 
-     _fillMissingFields([attr]);
 
-     cert.subject.attributes.push(attr);
 
-   };
 
-   cert.subject.attributes = [];
 
-   cert.subject.hash = null;
 
-   cert.extensions = [];
 
-   cert.publicKey = null;
 
-   cert.md = null;
 
-   /**
 
-    * Sets the subject of this certificate.
 
-    *
 
-    * @param attrs the array of subject attributes to use.
 
-    * @param uniqueId an optional a unique ID to use.
 
-    */
 
-   cert.setSubject = function(attrs, uniqueId) {
 
-     // set new attributes, clear hash
 
-     _fillMissingFields(attrs);
 
-     cert.subject.attributes = attrs;
 
-     delete cert.subject.uniqueId;
 
-     if(uniqueId) {
 
-       // TODO: support arbitrary bit length ids
 
-       cert.subject.uniqueId = uniqueId;
 
-     }
 
-     cert.subject.hash = null;
 
-   };
 
-   /**
 
-    * Sets the issuer of this certificate.
 
-    *
 
-    * @param attrs the array of issuer attributes to use.
 
-    * @param uniqueId an optional a unique ID to use.
 
-    */
 
-   cert.setIssuer = function(attrs, uniqueId) {
 
-     // set new attributes, clear hash
 
-     _fillMissingFields(attrs);
 
-     cert.issuer.attributes = attrs;
 
-     delete cert.issuer.uniqueId;
 
-     if(uniqueId) {
 
-       // TODO: support arbitrary bit length ids
 
-       cert.issuer.uniqueId = uniqueId;
 
-     }
 
-     cert.issuer.hash = null;
 
-   };
 
-   /**
 
-    * Sets the extensions of this certificate.
 
-    *
 
-    * @param exts the array of extensions to use.
 
-    */
 
-   cert.setExtensions = function(exts) {
 
-     for(var i = 0; i < exts.length; ++i) {
 
-       _fillMissingExtensionFields(exts[i], {cert: cert});
 
-     }
 
-     // set new extensions
 
-     cert.extensions = exts;
 
-   };
 
-   /**
 
-    * Gets an extension by its name or id.
 
-    *
 
-    * @param options the name to use or an object with:
 
-    *          name the name to use.
 
-    *          id the id to use.
 
-    *
 
-    * @return the extension or null if not found.
 
-    */
 
-   cert.getExtension = function(options) {
 
-     if(typeof options === 'string') {
 
-       options = {name: options};
 
-     }
 
-     var rval = null;
 
-     var ext;
 
-     for(var i = 0; rval === null && i < cert.extensions.length; ++i) {
 
-       ext = cert.extensions[i];
 
-       if(options.id && ext.id === options.id) {
 
-         rval = ext;
 
-       } else if(options.name && ext.name === options.name) {
 
-         rval = ext;
 
-       }
 
-     }
 
-     return rval;
 
-   };
 
-   /**
 
-    * Signs this certificate using the given private key.
 
-    *
 
-    * @param key the private key to sign with.
 
-    * @param md the message digest object to use (defaults to forge.md.sha1).
 
-    */
 
-   cert.sign = function(key, md) {
 
-     // TODO: get signature OID from private key
 
-     cert.md = md || forge.md.sha1.create();
 
-     var algorithmOid = oids[cert.md.algorithm + 'WithRSAEncryption'];
 
-     if(!algorithmOid) {
 
-       var error = new Error('Could not compute certificate digest. ' +
 
-         'Unknown message digest algorithm OID.');
 
-       error.algorithm = cert.md.algorithm;
 
-       throw error;
 
-     }
 
-     cert.signatureOid = cert.siginfo.algorithmOid = algorithmOid;
 
-     // get TBSCertificate, convert to DER
 
-     cert.tbsCertificate = pki.getTBSCertificate(cert);
 
-     var bytes = asn1.toDer(cert.tbsCertificate);
 
-     // digest and sign
 
-     cert.md.update(bytes.getBytes());
 
-     cert.signature = key.sign(cert.md);
 
-   };
 
-   /**
 
-    * Attempts verify the signature on the passed certificate using this
 
-    * certificate's public key.
 
-    *
 
-    * @param child the certificate to verify.
 
-    *
 
-    * @return true if verified, false if not.
 
-    */
 
-   cert.verify = function(child) {
 
-     var rval = false;
 
-     if(!cert.issued(child)) {
 
-       var issuer = child.issuer;
 
-       var subject = cert.subject;
 
-       var error = new Error(
 
-         'The parent certificate did not issue the given child ' +
 
-         'certificate; the child certificate\'s issuer does not match the ' +
 
-         'parent\'s subject.');
 
-       error.expectedIssuer = issuer.attributes;
 
-       error.actualIssuer = subject.attributes;
 
-       throw error;
 
-     }
 
-     var md = child.md;
 
-     if(md === null) {
 
-       // check signature OID for supported signature types
 
-       if(child.signatureOid in oids) {
 
-         var oid = oids[child.signatureOid];
 
-         switch(oid) {
 
-           case 'sha1WithRSAEncryption':
 
-             md = forge.md.sha1.create();
 
-             break;
 
-           case 'md5WithRSAEncryption':
 
-             md = forge.md.md5.create();
 
-             break;
 
-           case 'sha256WithRSAEncryption':
 
-             md = forge.md.sha256.create();
 
-             break;
 
-           case 'sha384WithRSAEncryption':
 
-             md = forge.md.sha384.create();
 
-             break;
 
-           case 'sha512WithRSAEncryption':
 
-             md = forge.md.sha512.create();
 
-             break;
 
-           case 'RSASSA-PSS':
 
-             md = forge.md.sha256.create();
 
-             break;
 
-         }
 
-       }
 
-       if(md === null) {
 
-         var error = new Error('Could not compute certificate digest. ' +
 
-           'Unknown signature OID.');
 
-         error.signatureOid = child.signatureOid;
 
-         throw error;
 
-       }
 
-       // produce DER formatted TBSCertificate and digest it
 
-       var tbsCertificate = child.tbsCertificate || pki.getTBSCertificate(child);
 
-       var bytes = asn1.toDer(tbsCertificate);
 
-       md.update(bytes.getBytes());
 
-     }
 
-     if(md !== null) {
 
-       var scheme;
 
-       switch(child.signatureOid) {
 
-         case oids.sha1WithRSAEncryption:
 
-           scheme = undefined; /* use PKCS#1 v1.5 padding scheme */
 
-           break;
 
-         case oids['RSASSA-PSS']:
 
-           var hash, mgf;
 
-           /* initialize mgf */
 
-           hash = oids[child.signatureParameters.mgf.hash.algorithmOid];
 
-           if(hash === undefined || forge.md[hash] === undefined) {
 
-             var error = new Error('Unsupported MGF hash function.');
 
-             error.oid = child.signatureParameters.mgf.hash.algorithmOid;
 
-             error.name = hash;
 
-             throw error;
 
-           }
 
-           mgf = oids[child.signatureParameters.mgf.algorithmOid];
 
-           if(mgf === undefined || forge.mgf[mgf] === undefined) {
 
-             var error = new Error('Unsupported MGF function.');
 
-             error.oid = child.signatureParameters.mgf.algorithmOid;
 
-             error.name = mgf;
 
-             throw error;
 
-           }
 
-           mgf = forge.mgf[mgf].create(forge.md[hash].create());
 
-           /* initialize hash function */
 
-           hash = oids[child.signatureParameters.hash.algorithmOid];
 
-           if(hash === undefined || forge.md[hash] === undefined) {
 
-             throw {
 
-               message: 'Unsupported RSASSA-PSS hash function.',
 
-               oid: child.signatureParameters.hash.algorithmOid,
 
-               name: hash
 
-             };
 
-           }
 
-           scheme = forge.pss.create(forge.md[hash].create(), mgf,
 
-             child.signatureParameters.saltLength);
 
-           break;
 
-       }
 
-       // verify signature on cert using public key
 
-       rval = cert.publicKey.verify(
 
-         md.digest().getBytes(), child.signature, scheme);
 
-     }
 
-     return rval;
 
-   };
 
-   /**
 
-    * Returns true if this certificate's issuer matches the passed
 
-    * certificate's subject. Note that no signature check is performed.
 
-    *
 
-    * @param parent the certificate to check.
 
-    *
 
-    * @return true if this certificate's issuer matches the passed certificate's
 
-    *         subject.
 
-    */
 
-   cert.isIssuer = function(parent) {
 
-     var rval = false;
 
-     var i = cert.issuer;
 
-     var s = parent.subject;
 
-     // compare hashes if present
 
-     if(i.hash && s.hash) {
 
-       rval = (i.hash === s.hash);
 
-     } else if(i.attributes.length === s.attributes.length) {
 
-       // all attributes are the same so issuer matches subject
 
-       rval = true;
 
-       var iattr, sattr;
 
-       for(var n = 0; rval && n < i.attributes.length; ++n) {
 
-         iattr = i.attributes[n];
 
-         sattr = s.attributes[n];
 
-         if(iattr.type !== sattr.type || iattr.value !== sattr.value) {
 
-           // attribute mismatch
 
-           rval = false;
 
-         }
 
-       }
 
-     }
 
-     return rval;
 
-   };
 
-   /**
 
-    * Returns true if this certificate's subject matches the issuer of the
 
-    * given certificate). Note that not signature check is performed.
 
-    *
 
-    * @param child the certificate to check.
 
-    *
 
-    * @return true if this certificate's subject matches the passed
 
-    *         certificate's issuer.
 
-    */
 
-   cert.issued = function(child) {
 
-     return child.isIssuer(cert);
 
-   };
 
-   /**
 
-    * Generates the subjectKeyIdentifier for this certificate as byte buffer.
 
-    *
 
-    * @return the subjectKeyIdentifier for this certificate as byte buffer.
 
-    */
 
-   cert.generateSubjectKeyIdentifier = function() {
 
-     /* See: 4.2.1.2 section of the the RFC3280, keyIdentifier is either:
 
-       (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
 
-         value of the BIT STRING subjectPublicKey (excluding the tag,
 
-         length, and number of unused bits).
 
-       (2) The keyIdentifier is composed of a four bit type field with
 
-         the value 0100 followed by the least significant 60 bits of the
 
-         SHA-1 hash of the value of the BIT STRING subjectPublicKey
 
-         (excluding the tag, length, and number of unused bit string bits).
 
-     */
 
-     // skipping the tag, length, and number of unused bits is the same
 
-     // as just using the RSAPublicKey (for RSA keys, which are the
 
-     // only ones supported)
 
-     return pki.getPublicKeyFingerprint(cert.publicKey, {type: 'RSAPublicKey'});
 
-   };
 
-   /**
 
-    * Verifies the subjectKeyIdentifier extension value for this certificate
 
-    * against its public key. If no extension is found, false will be
 
-    * returned.
 
-    *
 
-    * @return true if verified, false if not.
 
-    */
 
-   cert.verifySubjectKeyIdentifier = function() {
 
-     var oid = oids['subjectKeyIdentifier'];
 
-     for(var i = 0; i < cert.extensions.length; ++i) {
 
-       var ext = cert.extensions[i];
 
-       if(ext.id === oid) {
 
-         var ski = cert.generateSubjectKeyIdentifier().getBytes();
 
-         return (forge.util.hexToBytes(ext.subjectKeyIdentifier) === ski);
 
-       }
 
-     }
 
-     return false;
 
-   };
 
-   return cert;
 
- };
 
- /**
 
-  * Converts an X.509v3 RSA certificate from an ASN.1 object.
 
-  *
 
-  * Note: If the certificate is to be verified then compute hash should
 
-  * be set to true. There is currently no implementation for converting
 
-  * a certificate back to ASN.1 so the TBSCertificate part of the ASN.1
 
-  * object needs to be scanned before the cert object is created.
 
-  *
 
-  * @param obj the asn1 representation of an X.509v3 RSA certificate.
 
-  * @param computeHash true to compute the hash for verification.
 
-  *
 
-  * @return the certificate.
 
-  */
 
- pki.certificateFromAsn1 = function(obj, computeHash) {
 
-   // validate certificate and capture data
 
-   var capture = {};
 
-   var errors = [];
 
-   if(!asn1.validate(obj, x509CertificateValidator, capture, errors)) {
 
-     var error = new Error('Cannot read X.509 certificate. ' +
 
-       'ASN.1 object is not an X509v3 Certificate.');
 
-     error.errors = errors;
 
-     throw error;
 
-   }
 
-   // get oid
 
-   var oid = asn1.derToOid(capture.publicKeyOid);
 
-   if(oid !== pki.oids.rsaEncryption) {
 
-     throw new Error('Cannot read public key. OID is not RSA.');
 
-   }
 
-   // create certificate
 
-   var cert = pki.createCertificate();
 
-   cert.version = capture.certVersion ?
 
-     capture.certVersion.charCodeAt(0) : 0;
 
-   var serial = forge.util.createBuffer(capture.certSerialNumber);
 
-   cert.serialNumber = serial.toHex();
 
-   cert.signatureOid = forge.asn1.derToOid(capture.certSignatureOid);
 
-   cert.signatureParameters = _readSignatureParameters(
 
-     cert.signatureOid, capture.certSignatureParams, true);
 
-   cert.siginfo.algorithmOid = forge.asn1.derToOid(capture.certinfoSignatureOid);
 
-   cert.siginfo.parameters = _readSignatureParameters(cert.siginfo.algorithmOid,
 
-     capture.certinfoSignatureParams, false);
 
-   cert.signature = capture.certSignature;
 
-   var validity = [];
 
-   if(capture.certValidity1UTCTime !== undefined) {
 
-     validity.push(asn1.utcTimeToDate(capture.certValidity1UTCTime));
 
-   }
 
-   if(capture.certValidity2GeneralizedTime !== undefined) {
 
-     validity.push(asn1.generalizedTimeToDate(
 
-       capture.certValidity2GeneralizedTime));
 
-   }
 
-   if(capture.certValidity3UTCTime !== undefined) {
 
-     validity.push(asn1.utcTimeToDate(capture.certValidity3UTCTime));
 
-   }
 
-   if(capture.certValidity4GeneralizedTime !== undefined) {
 
-     validity.push(asn1.generalizedTimeToDate(
 
-       capture.certValidity4GeneralizedTime));
 
-   }
 
-   if(validity.length > 2) {
 
-     throw new Error('Cannot read notBefore/notAfter validity times; more ' +
 
-       'than two times were provided in the certificate.');
 
-   }
 
-   if(validity.length < 2) {
 
-     throw new Error('Cannot read notBefore/notAfter validity times; they ' +
 
-       'were not provided as either UTCTime or GeneralizedTime.');
 
-   }
 
-   cert.validity.notBefore = validity[0];
 
-   cert.validity.notAfter = validity[1];
 
-   // keep TBSCertificate to preserve signature when exporting
 
-   cert.tbsCertificate = capture.tbsCertificate;
 
-   if(computeHash) {
 
-     // check signature OID for supported signature types
 
-     cert.md = null;
 
-     if(cert.signatureOid in oids) {
 
-       var oid = oids[cert.signatureOid];
 
-       switch(oid) {
 
-         case 'sha1WithRSAEncryption':
 
-           cert.md = forge.md.sha1.create();
 
-           break;
 
-         case 'md5WithRSAEncryption':
 
-           cert.md = forge.md.md5.create();
 
-           break;
 
-         case 'sha256WithRSAEncryption':
 
-           cert.md = forge.md.sha256.create();
 
-           break;
 
-         case 'sha384WithRSAEncryption':
 
-           cert.md = forge.md.sha384.create();
 
-           break;
 
-         case 'sha512WithRSAEncryption':
 
-           cert.md = forge.md.sha512.create();
 
-           break;
 
-         case 'RSASSA-PSS':
 
-           cert.md = forge.md.sha256.create();
 
-           break;
 
-       }
 
-     }
 
-     if(cert.md === null) {
 
-       var error = new Error('Could not compute certificate digest. ' +
 
-         'Unknown signature OID.');
 
-       error.signatureOid = cert.signatureOid;
 
-       throw error;
 
-     }
 
-     // produce DER formatted TBSCertificate and digest it
 
-     var bytes = asn1.toDer(cert.tbsCertificate);
 
-     cert.md.update(bytes.getBytes());
 
-   }
 
-   // handle issuer, build issuer message digest
 
-   var imd = forge.md.sha1.create();
 
-   cert.issuer.getField = function(sn) {
 
-     return _getAttribute(cert.issuer, sn);
 
-   };
 
-   cert.issuer.addField = function(attr) {
 
-     _fillMissingFields([attr]);
 
-     cert.issuer.attributes.push(attr);
 
-   };
 
-   cert.issuer.attributes = pki.RDNAttributesAsArray(capture.certIssuer, imd);
 
-   if(capture.certIssuerUniqueId) {
 
-     cert.issuer.uniqueId = capture.certIssuerUniqueId;
 
-   }
 
-   cert.issuer.hash = imd.digest().toHex();
 
-   // handle subject, build subject message digest
 
-   var smd = forge.md.sha1.create();
 
-   cert.subject.getField = function(sn) {
 
-     return _getAttribute(cert.subject, sn);
 
-   };
 
-   cert.subject.addField = function(attr) {
 
-     _fillMissingFields([attr]);
 
-     cert.subject.attributes.push(attr);
 
-   };
 
-   cert.subject.attributes = pki.RDNAttributesAsArray(capture.certSubject, smd);
 
-   if(capture.certSubjectUniqueId) {
 
-     cert.subject.uniqueId = capture.certSubjectUniqueId;
 
-   }
 
-   cert.subject.hash = smd.digest().toHex();
 
-   // handle extensions
 
-   if(capture.certExtensions) {
 
-     cert.extensions = pki.certificateExtensionsFromAsn1(capture.certExtensions);
 
-   } else {
 
-     cert.extensions = [];
 
-   }
 
-   // convert RSA public key from ASN.1
 
-   cert.publicKey = pki.publicKeyFromAsn1(capture.subjectPublicKeyInfo);
 
-   return cert;
 
- };
 
- /**
 
-  * Converts an ASN.1 extensions object (with extension sequences as its
 
-  * values) into an array of extension objects with types and values.
 
-  *
 
-  * Supported extensions:
 
-  *
 
-  * id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
 
-  * KeyUsage ::= BIT STRING {
 
-  *   digitalSignature        (0),
 
-  *   nonRepudiation          (1),
 
-  *   keyEncipherment         (2),
 
-  *   dataEncipherment        (3),
 
-  *   keyAgreement            (4),
 
-  *   keyCertSign             (5),
 
-  *   cRLSign                 (6),
 
-  *   encipherOnly            (7),
 
-  *   decipherOnly            (8)
 
-  * }
 
-  *
 
-  * id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
 
-  * BasicConstraints ::= SEQUENCE {
 
-  *   cA                      BOOLEAN DEFAULT FALSE,
 
-  *   pathLenConstraint       INTEGER (0..MAX) OPTIONAL
 
-  * }
 
-  *
 
-  * subjectAltName EXTENSION ::= {
 
-  *   SYNTAX GeneralNames
 
-  *   IDENTIFIED BY id-ce-subjectAltName
 
-  * }
 
-  *
 
-  * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
 
-  *
 
-  * GeneralName ::= CHOICE {
 
-  *   otherName      [0] INSTANCE OF OTHER-NAME,
 
-  *   rfc822Name     [1] IA5String,
 
-  *   dNSName        [2] IA5String,
 
-  *   x400Address    [3] ORAddress,
 
-  *   directoryName  [4] Name,
 
-  *   ediPartyName   [5] EDIPartyName,
 
-  *   uniformResourceIdentifier [6] IA5String,
 
-  *   IPAddress      [7] OCTET STRING,
 
-  *   registeredID   [8] OBJECT IDENTIFIER
 
-  * }
 
-  *
 
-  * OTHER-NAME ::= TYPE-IDENTIFIER
 
-  *
 
-  * EDIPartyName ::= SEQUENCE {
 
-  *   nameAssigner [0] DirectoryString {ub-name} OPTIONAL,
 
-  *   partyName    [1] DirectoryString {ub-name}
 
-  * }
 
-  *
 
-  * @param exts the extensions ASN.1 with extension sequences to parse.
 
-  *
 
-  * @return the array.
 
-  */
 
- pki.certificateExtensionsFromAsn1 = function(exts) {
 
-   var rval = [];
 
-   for(var i = 0; i < exts.value.length; ++i) {
 
-     // get extension sequence
 
-     var extseq = exts.value[i];
 
-     for(var ei = 0; ei < extseq.value.length; ++ei) {
 
-       rval.push(pki.certificateExtensionFromAsn1(extseq.value[ei]));
 
-     }
 
-   }
 
-   return rval;
 
- };
 
- /**
 
-  * Parses a single certificate extension from ASN.1.
 
-  *
 
-  * @param ext the extension in ASN.1 format.
 
-  *
 
-  * @return the parsed extension as an object.
 
-  */
 
- pki.certificateExtensionFromAsn1 = function(ext) {
 
-   // an extension has:
 
-   // [0] extnID      OBJECT IDENTIFIER
 
-   // [1] critical    BOOLEAN DEFAULT FALSE
 
-   // [2] extnValue   OCTET STRING
 
-   var e = {};
 
-   e.id = asn1.derToOid(ext.value[0].value);
 
-   e.critical = false;
 
-   if(ext.value[1].type === asn1.Type.BOOLEAN) {
 
-     e.critical = (ext.value[1].value.charCodeAt(0) !== 0x00);
 
-     e.value = ext.value[2].value;
 
-   } else {
 
-     e.value = ext.value[1].value;
 
-   }
 
-   // if the oid is known, get its name
 
-   if(e.id in oids) {
 
-     e.name = oids[e.id];
 
-     // handle key usage
 
-     if(e.name === 'keyUsage') {
 
-       // get value as BIT STRING
 
-       var ev = asn1.fromDer(e.value);
 
-       var b2 = 0x00;
 
-       var b3 = 0x00;
 
-       if(ev.value.length > 1) {
 
-         // skip first byte, just indicates unused bits which
 
-         // will be padded with 0s anyway
 
-         // get bytes with flag bits
 
-         b2 = ev.value.charCodeAt(1);
 
-         b3 = ev.value.length > 2 ? ev.value.charCodeAt(2) : 0;
 
-       }
 
-       // set flags
 
-       e.digitalSignature = (b2 & 0x80) === 0x80;
 
-       e.nonRepudiation = (b2 & 0x40) === 0x40;
 
-       e.keyEncipherment = (b2 & 0x20) === 0x20;
 
-       e.dataEncipherment = (b2 & 0x10) === 0x10;
 
-       e.keyAgreement = (b2 & 0x08) === 0x08;
 
-       e.keyCertSign = (b2 & 0x04) === 0x04;
 
-       e.cRLSign = (b2 & 0x02) === 0x02;
 
-       e.encipherOnly = (b2 & 0x01) === 0x01;
 
-       e.decipherOnly = (b3 & 0x80) === 0x80;
 
-     } else if(e.name === 'basicConstraints') {
 
-       // handle basic constraints
 
-       // get value as SEQUENCE
 
-       var ev = asn1.fromDer(e.value);
 
-       // get cA BOOLEAN flag (defaults to false)
 
-       if(ev.value.length > 0 && ev.value[0].type === asn1.Type.BOOLEAN) {
 
-         e.cA = (ev.value[0].value.charCodeAt(0) !== 0x00);
 
-       } else {
 
-         e.cA = false;
 
-       }
 
-       // get path length constraint
 
-       var value = null;
 
-       if(ev.value.length > 0 && ev.value[0].type === asn1.Type.INTEGER) {
 
-         value = ev.value[0].value;
 
-       } else if(ev.value.length > 1) {
 
-         value = ev.value[1].value;
 
-       }
 
-       if(value !== null) {
 
-         e.pathLenConstraint = asn1.derToInteger(value);
 
-       }
 
-     } else if(e.name === 'extKeyUsage') {
 
-       // handle extKeyUsage
 
-       // value is a SEQUENCE of OIDs
 
-       var ev = asn1.fromDer(e.value);
 
-       for(var vi = 0; vi < ev.value.length; ++vi) {
 
-         var oid = asn1.derToOid(ev.value[vi].value);
 
-         if(oid in oids) {
 
-           e[oids[oid]] = true;
 
-         } else {
 
-           e[oid] = true;
 
-         }
 
-       }
 
-     } else if(e.name === 'nsCertType') {
 
-       // handle nsCertType
 
-       // get value as BIT STRING
 
-       var ev = asn1.fromDer(e.value);
 
-       var b2 = 0x00;
 
-       if(ev.value.length > 1) {
 
-         // skip first byte, just indicates unused bits which
 
-         // will be padded with 0s anyway
 
-         // get bytes with flag bits
 
-         b2 = ev.value.charCodeAt(1);
 
-       }
 
-       // set flags
 
-       e.client = (b2 & 0x80) === 0x80;
 
-       e.server = (b2 & 0x40) === 0x40;
 
-       e.email = (b2 & 0x20) === 0x20;
 
-       e.objsign = (b2 & 0x10) === 0x10;
 
-       e.reserved = (b2 & 0x08) === 0x08;
 
-       e.sslCA = (b2 & 0x04) === 0x04;
 
-       e.emailCA = (b2 & 0x02) === 0x02;
 
-       e.objCA = (b2 & 0x01) === 0x01;
 
-     } else if(
 
-       e.name === 'subjectAltName' ||
 
-       e.name === 'issuerAltName') {
 
-       // handle subjectAltName/issuerAltName
 
-       e.altNames = [];
 
-       // ev is a SYNTAX SEQUENCE
 
-       var gn;
 
-       var ev = asn1.fromDer(e.value);
 
-       for(var n = 0; n < ev.value.length; ++n) {
 
-         // get GeneralName
 
-         gn = ev.value[n];
 
-         var altName = {
 
-           type: gn.type,
 
-           value: gn.value
 
-         };
 
-         e.altNames.push(altName);
 
-         // Note: Support for types 1,2,6,7,8
 
-         switch(gn.type) {
 
-           // rfc822Name
 
-           case 1:
 
-           // dNSName
 
-           case 2:
 
-           // uniformResourceIdentifier (URI)
 
-           case 6:
 
-             break;
 
-           // IPAddress
 
-           case 7:
 
-             // convert to IPv4/IPv6 string representation
 
-             altName.ip = forge.util.bytesToIP(gn.value);
 
-             break;
 
-           // registeredID
 
-           case 8:
 
-             altName.oid = asn1.derToOid(gn.value);
 
-             break;
 
-           default:
 
-             // unsupported
 
-         }
 
-       }
 
-     } else if(e.name === 'subjectKeyIdentifier') {
 
-       // value is an OCTETSTRING w/the hash of the key-type specific
 
-       // public key structure (eg: RSAPublicKey)
 
-       var ev = asn1.fromDer(e.value);
 
-       e.subjectKeyIdentifier = forge.util.bytesToHex(ev.value);
 
-     }
 
-   }
 
-   return e;
 
- };
 
- /**
 
-  * Converts a PKCS#10 certification request (CSR) from an ASN.1 object.
 
-  *
 
-  * Note: If the certification request is to be verified then compute hash
 
-  * should be set to true. There is currently no implementation for converting
 
-  * a certificate back to ASN.1 so the CertificationRequestInfo part of the
 
-  * ASN.1 object needs to be scanned before the csr object is created.
 
-  *
 
-  * @param obj the asn1 representation of a PKCS#10 certification request (CSR).
 
-  * @param computeHash true to compute the hash for verification.
 
-  *
 
-  * @return the certification request (CSR).
 
-  */
 
- pki.certificationRequestFromAsn1 = function(obj, computeHash) {
 
-   // validate certification request and capture data
 
-   var capture = {};
 
-   var errors = [];
 
-   if(!asn1.validate(obj, certificationRequestValidator, capture, errors)) {
 
-     var error = new Error('Cannot read PKCS#10 certificate request. ' +
 
-       'ASN.1 object is not a PKCS#10 CertificationRequest.');
 
-     error.errors = errors;
 
-     throw error;
 
-   }
 
-   // get oid
 
-   var oid = asn1.derToOid(capture.publicKeyOid);
 
-   if(oid !== pki.oids.rsaEncryption) {
 
-     throw new Error('Cannot read public key. OID is not RSA.');
 
-   }
 
-   // create certification request
 
-   var csr = pki.createCertificationRequest();
 
-   csr.version = capture.csrVersion ? capture.csrVersion.charCodeAt(0) : 0;
 
-   csr.signatureOid = forge.asn1.derToOid(capture.csrSignatureOid);
 
-   csr.signatureParameters = _readSignatureParameters(
 
-     csr.signatureOid, capture.csrSignatureParams, true);
 
-   csr.siginfo.algorithmOid = forge.asn1.derToOid(capture.csrSignatureOid);
 
-   csr.siginfo.parameters = _readSignatureParameters(
 
-     csr.siginfo.algorithmOid, capture.csrSignatureParams, false);
 
-   csr.signature = capture.csrSignature;
 
-   // keep CertificationRequestInfo to preserve signature when exporting
 
-   csr.certificationRequestInfo = capture.certificationRequestInfo;
 
-   if(computeHash) {
 
-     // check signature OID for supported signature types
 
-     csr.md = null;
 
-     if(csr.signatureOid in oids) {
 
-       var oid = oids[csr.signatureOid];
 
-       switch(oid) {
 
-         case 'sha1WithRSAEncryption':
 
-           csr.md = forge.md.sha1.create();
 
-           break;
 
-         case 'md5WithRSAEncryption':
 
-           csr.md = forge.md.md5.create();
 
-           break;
 
-         case 'sha256WithRSAEncryption':
 
-           csr.md = forge.md.sha256.create();
 
-           break;
 
-         case 'sha384WithRSAEncryption':
 
-           csr.md = forge.md.sha384.create();
 
-           break;
 
-         case 'sha512WithRSAEncryption':
 
-           csr.md = forge.md.sha512.create();
 
-           break;
 
-         case 'RSASSA-PSS':
 
-           csr.md = forge.md.sha256.create();
 
-           break;
 
-       }
 
-     }
 
-     if(csr.md === null) {
 
-       var error = new Error('Could not compute certification request digest. ' +
 
-         'Unknown signature OID.');
 
-       error.signatureOid = csr.signatureOid;
 
-       throw error;
 
-     }
 
-     // produce DER formatted CertificationRequestInfo and digest it
 
-     var bytes = asn1.toDer(csr.certificationRequestInfo);
 
-     csr.md.update(bytes.getBytes());
 
-   }
 
-   // handle subject, build subject message digest
 
-   var smd = forge.md.sha1.create();
 
-   csr.subject.getField = function(sn) {
 
-     return _getAttribute(csr.subject, sn);
 
-   };
 
-   csr.subject.addField = function(attr) {
 
-     _fillMissingFields([attr]);
 
-     csr.subject.attributes.push(attr);
 
-   };
 
-   csr.subject.attributes = pki.RDNAttributesAsArray(
 
-     capture.certificationRequestInfoSubject, smd);
 
-   csr.subject.hash = smd.digest().toHex();
 
-   // convert RSA public key from ASN.1
 
-   csr.publicKey = pki.publicKeyFromAsn1(capture.subjectPublicKeyInfo);
 
-   // convert attributes from ASN.1
 
-   csr.getAttribute = function(sn) {
 
-     return _getAttribute(csr, sn);
 
-   };
 
-   csr.addAttribute = function(attr) {
 
-     _fillMissingFields([attr]);
 
-     csr.attributes.push(attr);
 
-   };
 
-   csr.attributes = pki.CRIAttributesAsArray(
 
-     capture.certificationRequestInfoAttributes || []);
 
-   return csr;
 
- };
 
- /**
 
-  * Creates an empty certification request (a CSR or certificate signing
 
-  * request). Once created, its public key and attributes can be set and then
 
-  * it can be signed.
 
-  *
 
-  * @return the empty certification request.
 
-  */
 
- pki.createCertificationRequest = function() {
 
-   var csr = {};
 
-   csr.version = 0x00;
 
-   csr.signatureOid = null;
 
-   csr.signature = null;
 
-   csr.siginfo = {};
 
-   csr.siginfo.algorithmOid = null;
 
-   csr.subject = {};
 
-   csr.subject.getField = function(sn) {
 
-     return _getAttribute(csr.subject, sn);
 
-   };
 
-   csr.subject.addField = function(attr) {
 
-     _fillMissingFields([attr]);
 
-     csr.subject.attributes.push(attr);
 
-   };
 
-   csr.subject.attributes = [];
 
-   csr.subject.hash = null;
 
-   csr.publicKey = null;
 
-   csr.attributes = [];
 
-   csr.getAttribute = function(sn) {
 
-     return _getAttribute(csr, sn);
 
-   };
 
-   csr.addAttribute = function(attr) {
 
-     _fillMissingFields([attr]);
 
-     csr.attributes.push(attr);
 
-   };
 
-   csr.md = null;
 
-   /**
 
-    * Sets the subject of this certification request.
 
-    *
 
-    * @param attrs the array of subject attributes to use.
 
-    */
 
-   csr.setSubject = function(attrs) {
 
-     // set new attributes
 
-     _fillMissingFields(attrs);
 
-     csr.subject.attributes = attrs;
 
-     csr.subject.hash = null;
 
-   };
 
-   /**
 
-    * Sets the attributes of this certification request.
 
-    *
 
-    * @param attrs the array of attributes to use.
 
-    */
 
-   csr.setAttributes = function(attrs) {
 
-     // set new attributes
 
-     _fillMissingFields(attrs);
 
-     csr.attributes = attrs;
 
-   };
 
-   /**
 
-    * Signs this certification request using the given private key.
 
-    *
 
-    * @param key the private key to sign with.
 
-    * @param md the message digest object to use (defaults to forge.md.sha1).
 
-    */
 
-   csr.sign = function(key, md) {
 
-     // TODO: get signature OID from private key
 
-     csr.md = md || forge.md.sha1.create();
 
-     var algorithmOid = oids[csr.md.algorithm + 'WithRSAEncryption'];
 
-     if(!algorithmOid) {
 
-       var error = new Error('Could not compute certification request digest. ' +
 
-         'Unknown message digest algorithm OID.');
 
-       error.algorithm = csr.md.algorithm;
 
-       throw error;
 
-     }
 
-     csr.signatureOid = csr.siginfo.algorithmOid = algorithmOid;
 
-     // get CertificationRequestInfo, convert to DER
 
-     csr.certificationRequestInfo = pki.getCertificationRequestInfo(csr);
 
-     var bytes = asn1.toDer(csr.certificationRequestInfo);
 
-     // digest and sign
 
-     csr.md.update(bytes.getBytes());
 
-     csr.signature = key.sign(csr.md);
 
-   };
 
-   /**
 
-    * Attempts verify the signature on the passed certification request using
 
-    * its public key.
 
-    *
 
-    * A CSR that has been exported to a file in PEM format can be verified using
 
-    * OpenSSL using this command:
 
-    *
 
-    * openssl req -in <the-csr-pem-file> -verify -noout -text
 
-    *
 
-    * @return true if verified, false if not.
 
-    */
 
-   csr.verify = function() {
 
-     var rval = false;
 
-     var md = csr.md;
 
-     if(md === null) {
 
-       // check signature OID for supported signature types
 
-       if(csr.signatureOid in oids) {
 
-         // TODO: create DRY `OID to md` function
 
-         var oid = oids[csr.signatureOid];
 
-         switch(oid) {
 
-           case 'sha1WithRSAEncryption':
 
-             md = forge.md.sha1.create();
 
-             break;
 
-           case 'md5WithRSAEncryption':
 
-             md = forge.md.md5.create();
 
-             break;
 
-           case 'sha256WithRSAEncryption':
 
-             md = forge.md.sha256.create();
 
-             break;
 
-           case 'sha384WithRSAEncryption':
 
-             md = forge.md.sha384.create();
 
-             break;
 
-           case 'sha512WithRSAEncryption':
 
-             md = forge.md.sha512.create();
 
-             break;
 
-           case 'RSASSA-PSS':
 
-             md = forge.md.sha256.create();
 
-             break;
 
-         }
 
-       }
 
-       if(md === null) {
 
-         var error = new Error(
 
-           'Could not compute certification request digest. ' +
 
-           'Unknown signature OID.');
 
-         error.signatureOid = csr.signatureOid;
 
-         throw error;
 
-       }
 
-       // produce DER formatted CertificationRequestInfo and digest it
 
-       var cri = csr.certificationRequestInfo ||
 
-         pki.getCertificationRequestInfo(csr);
 
-       var bytes = asn1.toDer(cri);
 
-       md.update(bytes.getBytes());
 
-     }
 
-     if(md !== null) {
 
-       var scheme;
 
-       switch(csr.signatureOid) {
 
-         case oids.sha1WithRSAEncryption:
 
-           /* use PKCS#1 v1.5 padding scheme */
 
-           break;
 
-         case oids['RSASSA-PSS']:
 
-           var hash, mgf;
 
-           /* initialize mgf */
 
-           hash = oids[csr.signatureParameters.mgf.hash.algorithmOid];
 
-           if(hash === undefined || forge.md[hash] === undefined) {
 
-             var error = new Error('Unsupported MGF hash function.');
 
-             error.oid = csr.signatureParameters.mgf.hash.algorithmOid;
 
-             error.name = hash;
 
-             throw error;
 
-           }
 
-           mgf = oids[csr.signatureParameters.mgf.algorithmOid];
 
-           if(mgf === undefined || forge.mgf[mgf] === undefined) {
 
-             var error = new Error('Unsupported MGF function.');
 
-             error.oid = csr.signatureParameters.mgf.algorithmOid;
 
-             error.name = mgf;
 
-             throw error;
 
-           }
 
-           mgf = forge.mgf[mgf].create(forge.md[hash].create());
 
-           /* initialize hash function */
 
-           hash = oids[csr.signatureParameters.hash.algorithmOid];
 
-           if(hash === undefined || forge.md[hash] === undefined) {
 
-             var error = new Error('Unsupported RSASSA-PSS hash function.');
 
-             error.oid = csr.signatureParameters.hash.algorithmOid;
 
-             error.name = hash;
 
-             throw error;
 
-           }
 
-           scheme = forge.pss.create(forge.md[hash].create(), mgf,
 
-             csr.signatureParameters.saltLength);
 
-           break;
 
-       }
 
-       // verify signature on csr using its public key
 
-       rval = csr.publicKey.verify(
 
-         md.digest().getBytes(), csr.signature, scheme);
 
-     }
 
-     return rval;
 
-   };
 
-   return csr;
 
- };
 
- /**
 
-  * Converts an X.509 subject or issuer to an ASN.1 RDNSequence.
 
-  *
 
-  * @param obj the subject or issuer (distinguished name).
 
-  *
 
-  * @return the ASN.1 RDNSequence.
 
-  */
 
- function _dnToAsn1(obj) {
 
-   // create an empty RDNSequence
 
-   var rval = asn1.create(
 
-     asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-   // iterate over attributes
 
-   var attr, set;
 
-   var attrs = obj.attributes;
 
-   for(var i = 0; i < attrs.length; ++i) {
 
-     attr = attrs[i];
 
-     var value = attr.value;
 
-     // reuse tag class for attribute value if available
 
-     var valueTagClass = asn1.Type.PRINTABLESTRING;
 
-     if('valueTagClass' in attr) {
 
-       valueTagClass = attr.valueTagClass;
 
-       if(valueTagClass === asn1.Type.UTF8) {
 
-         value = forge.util.encodeUtf8(value);
 
-       }
 
-       // FIXME: handle more encodings
 
-     }
 
-     // create a RelativeDistinguishedName set
 
-     // each value in the set is an AttributeTypeAndValue first
 
-     // containing the type (an OID) and second the value
 
-     set = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [
 
-       asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-         // AttributeType
 
-         asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-           asn1.oidToDer(attr.type).getBytes()),
 
-         // AttributeValue
 
-         asn1.create(asn1.Class.UNIVERSAL, valueTagClass, false, value)
 
-       ])
 
-     ]);
 
-     rval.value.push(set);
 
-   }
 
-   return rval;
 
- }
 
- /**
 
-  * Gets all printable attributes (typically of an issuer or subject) in a
 
-  * simplified JSON format for display.
 
-  *
 
-  * @param attrs the attributes.
 
-  *
 
-  * @return the JSON for display.
 
-  */
 
- function _getAttributesAsJson(attrs) {
 
-   var rval = {};
 
-   for(var i = 0; i < attrs.length; ++i) {
 
-     var attr = attrs[i];
 
-     if(attr.shortName && (
 
-       attr.valueTagClass === asn1.Type.UTF8 ||
 
-       attr.valueTagClass === asn1.Type.PRINTABLESTRING ||
 
-       attr.valueTagClass === asn1.Type.IA5STRING)) {
 
-       var value = attr.value;
 
-       if(attr.valueTagClass === asn1.Type.UTF8) {
 
-         value = forge.util.encodeUtf8(attr.value);
 
-       }
 
-       if(!(attr.shortName in rval)) {
 
-         rval[attr.shortName] = value;
 
-       } else if(forge.util.isArray(rval[attr.shortName])) {
 
-         rval[attr.shortName].push(value);
 
-       } else {
 
-         rval[attr.shortName] = [rval[attr.shortName], value];
 
-       }
 
-     }
 
-   }
 
-   return rval;
 
- }
 
- /**
 
-  * Fills in missing fields in attributes.
 
-  *
 
-  * @param attrs the attributes to fill missing fields in.
 
-  */
 
- function _fillMissingFields(attrs) {
 
-   var attr;
 
-   for(var i = 0; i < attrs.length; ++i) {
 
-     attr = attrs[i];
 
-     // populate missing name
 
-     if(typeof attr.name === 'undefined') {
 
-       if(attr.type && attr.type in pki.oids) {
 
-         attr.name = pki.oids[attr.type];
 
-       } else if(attr.shortName && attr.shortName in _shortNames) {
 
-         attr.name = pki.oids[_shortNames[attr.shortName]];
 
-       }
 
-     }
 
-     // populate missing type (OID)
 
-     if(typeof attr.type === 'undefined') {
 
-       if(attr.name && attr.name in pki.oids) {
 
-         attr.type = pki.oids[attr.name];
 
-       } else {
 
-         var error = new Error('Attribute type not specified.');
 
-         error.attribute = attr;
 
-         throw error;
 
-       }
 
-     }
 
-     // populate missing shortname
 
-     if(typeof attr.shortName === 'undefined') {
 
-       if(attr.name && attr.name in _shortNames) {
 
-         attr.shortName = _shortNames[attr.name];
 
-       }
 
-     }
 
-     // convert extensions to value
 
-     if(attr.type === oids.extensionRequest) {
 
-       attr.valueConstructed = true;
 
-       attr.valueTagClass = asn1.Type.SEQUENCE;
 
-       if(!attr.value && attr.extensions) {
 
-         attr.value = [];
 
-         for(var ei = 0; ei < attr.extensions.length; ++ei) {
 
-           attr.value.push(pki.certificateExtensionToAsn1(
 
-             _fillMissingExtensionFields(attr.extensions[ei])));
 
-         }
 
-       }
 
-     }
 
-     if(typeof attr.value === 'undefined') {
 
-       var error = new Error('Attribute value not specified.');
 
-       error.attribute = attr;
 
-       throw error;
 
-     }
 
-   }
 
- }
 
- /**
 
-  * Fills in missing fields in certificate extensions.
 
-  *
 
-  * @param e the extension.
 
-  * @param [options] the options to use.
 
-  *          [cert] the certificate the extensions are for.
 
-  *
 
-  * @return the extension.
 
-  */
 
- function _fillMissingExtensionFields(e, options) {
 
-   options = options || {};
 
-   // populate missing name
 
-   if(typeof e.name === 'undefined') {
 
-     if(e.id && e.id in pki.oids) {
 
-       e.name = pki.oids[e.id];
 
-     }
 
-   }
 
-   // populate missing id
 
-   if(typeof e.id === 'undefined') {
 
-     if(e.name && e.name in pki.oids) {
 
-       e.id = pki.oids[e.name];
 
-     } else {
 
-       var error = new Error('Extension ID not specified.');
 
-       error.extension = e;
 
-       throw error;
 
-     }
 
-   }
 
-   if(typeof e.value !== 'undefined') {
 
-     return e;
 
-   }
 
-   // handle missing value:
 
-   // value is a BIT STRING
 
-   if(e.name === 'keyUsage') {
 
-     // build flags
 
-     var unused = 0;
 
-     var b2 = 0x00;
 
-     var b3 = 0x00;
 
-     if(e.digitalSignature) {
 
-       b2 |= 0x80;
 
-       unused = 7;
 
-     }
 
-     if(e.nonRepudiation) {
 
-       b2 |= 0x40;
 
-       unused = 6;
 
-     }
 
-     if(e.keyEncipherment) {
 
-       b2 |= 0x20;
 
-       unused = 5;
 
-     }
 
-     if(e.dataEncipherment) {
 
-       b2 |= 0x10;
 
-       unused = 4;
 
-     }
 
-     if(e.keyAgreement) {
 
-       b2 |= 0x08;
 
-       unused = 3;
 
-     }
 
-     if(e.keyCertSign) {
 
-       b2 |= 0x04;
 
-       unused = 2;
 
-     }
 
-     if(e.cRLSign) {
 
-       b2 |= 0x02;
 
-       unused = 1;
 
-     }
 
-     if(e.encipherOnly) {
 
-       b2 |= 0x01;
 
-       unused = 0;
 
-     }
 
-     if(e.decipherOnly) {
 
-       b3 |= 0x80;
 
-       unused = 7;
 
-     }
 
-     // create bit string
 
-     var value = String.fromCharCode(unused);
 
-     if(b3 !== 0) {
 
-       value += String.fromCharCode(b2) + String.fromCharCode(b3);
 
-     } else if(b2 !== 0) {
 
-       value += String.fromCharCode(b2);
 
-     }
 
-     e.value = asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, value);
 
-   } else if(e.name === 'basicConstraints') {
 
-     // basicConstraints is a SEQUENCE
 
-     e.value = asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-     // cA BOOLEAN flag defaults to false
 
-     if(e.cA) {
 
-       e.value.value.push(asn1.create(
 
-         asn1.Class.UNIVERSAL, asn1.Type.BOOLEAN, false,
 
-         String.fromCharCode(0xFF)));
 
-     }
 
-     if('pathLenConstraint' in e) {
 
-       e.value.value.push(asn1.create(
 
-         asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
 
-         asn1.integerToDer(e.pathLenConstraint).getBytes()));
 
-     }
 
-   } else if(e.name === 'extKeyUsage') {
 
-     // extKeyUsage is a SEQUENCE of OIDs
 
-     e.value = asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-     var seq = e.value.value;
 
-     for(var key in e) {
 
-       if(e[key] !== true) {
 
-         continue;
 
-       }
 
-       // key is name in OID map
 
-       if(key in oids) {
 
-         seq.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID,
 
-           false, asn1.oidToDer(oids[key]).getBytes()));
 
-       } else if(key.indexOf('.') !== -1) {
 
-         // assume key is an OID
 
-         seq.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID,
 
-           false, asn1.oidToDer(key).getBytes()));
 
-       }
 
-     }
 
-   } else if(e.name === 'nsCertType') {
 
-     // nsCertType is a BIT STRING
 
-     // build flags
 
-     var unused = 0;
 
-     var b2 = 0x00;
 
-     if(e.client) {
 
-       b2 |= 0x80;
 
-       unused = 7;
 
-     }
 
-     if(e.server) {
 
-       b2 |= 0x40;
 
-       unused = 6;
 
-     }
 
-     if(e.email) {
 
-       b2 |= 0x20;
 
-       unused = 5;
 
-     }
 
-     if(e.objsign) {
 
-       b2 |= 0x10;
 
-       unused = 4;
 
-     }
 
-     if(e.reserved) {
 
-       b2 |= 0x08;
 
-       unused = 3;
 
-     }
 
-     if(e.sslCA) {
 
-       b2 |= 0x04;
 
-       unused = 2;
 
-     }
 
-     if(e.emailCA) {
 
-       b2 |= 0x02;
 
-       unused = 1;
 
-     }
 
-     if(e.objCA) {
 
-       b2 |= 0x01;
 
-       unused = 0;
 
-     }
 
-     // create bit string
 
-     var value = String.fromCharCode(unused);
 
-     if(b2 !== 0) {
 
-       value += String.fromCharCode(b2);
 
-     }
 
-     e.value = asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, value);
 
-   } else if(e.name === 'subjectAltName' || e.name === 'issuerAltName') {
 
-     // SYNTAX SEQUENCE
 
-     e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-     var altName;
 
-     for(var n = 0; n < e.altNames.length; ++n) {
 
-       altName = e.altNames[n];
 
-       var value = altName.value;
 
-       // handle IP
 
-       if(altName.type === 7 && altName.ip) {
 
-         value = forge.util.bytesFromIP(altName.ip);
 
-         if(value === null) {
 
-           var error = new Error(
 
-             'Extension "ip" value is not a valid IPv4 or IPv6 address.');
 
-           error.extension = e;
 
-           throw error;
 
-         }
 
-       } else if(altName.type === 8) {
 
-         // handle OID
 
-         if(altName.oid) {
 
-           value = asn1.oidToDer(asn1.oidToDer(altName.oid));
 
-         } else {
 
-           // deprecated ... convert value to OID
 
-           value = asn1.oidToDer(value);
 
-         }
 
-       }
 
-       e.value.value.push(asn1.create(
 
-         asn1.Class.CONTEXT_SPECIFIC, altName.type, false,
 
-         value));
 
-     }
 
-   } else if(e.name === 'nsComment' && options.cert) {
 
-     // sanity check value is ASCII (req'd) and not too big
 
-     if(!(/^[\x00-\x7F]*$/.test(e.comment)) ||
 
-       (e.comment.length < 1) || (e.comment.length > 128)) {
 
-       throw new Error('Invalid "nsComment" content.');
 
-     }
 
-     // IA5STRING opaque comment
 
-     e.value = asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.IA5STRING, false, e.comment);
 
-   } else if(e.name === 'subjectKeyIdentifier' && options.cert) {
 
-     var ski = options.cert.generateSubjectKeyIdentifier();
 
-     e.subjectKeyIdentifier = ski.toHex();
 
-     // OCTETSTRING w/digest
 
-     e.value = asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, ski.getBytes());
 
-   } else if(e.name === 'authorityKeyIdentifier' && options.cert) {
 
-     // SYNTAX SEQUENCE
 
-     e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-     var seq = e.value.value;
 
-     if(e.keyIdentifier) {
 
-       var keyIdentifier = (e.keyIdentifier === true ?
 
-         options.cert.generateSubjectKeyIdentifier().getBytes() :
 
-         e.keyIdentifier);
 
-       seq.push(
 
-         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, false, keyIdentifier));
 
-     }
 
-     if(e.authorityCertIssuer) {
 
-       var authorityCertIssuer = [
 
-         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 4, true, [
 
-           _dnToAsn1(e.authorityCertIssuer === true ?
 
-             options.cert.issuer : e.authorityCertIssuer)
 
-         ])
 
-       ];
 
-       seq.push(
 
-         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, authorityCertIssuer));
 
-     }
 
-     if(e.serialNumber) {
 
-       var serialNumber = forge.util.hexToBytes(e.serialNumber === true ?
 
-         options.cert.serialNumber : e.serialNumber);
 
-       seq.push(
 
-         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, false, serialNumber));
 
-     }
 
-   } else if(e.name === 'cRLDistributionPoints') {
 
-     e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-     var seq = e.value.value;
 
-     // Create sub SEQUENCE of DistributionPointName
 
-     var subSeq = asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-     // Create fullName CHOICE
 
-     var fullNameGeneralNames = asn1.create(
 
-       asn1.Class.CONTEXT_SPECIFIC, 0, true, []);
 
-     var altName;
 
-     for(var n = 0; n < e.altNames.length; ++n) {
 
-       altName = e.altNames[n];
 
-       var value = altName.value;
 
-       // handle IP
 
-       if(altName.type === 7 && altName.ip) {
 
-         value = forge.util.bytesFromIP(altName.ip);
 
-         if(value === null) {
 
-           var error = new Error(
 
-             'Extension "ip" value is not a valid IPv4 or IPv6 address.');
 
-           error.extension = e;
 
-           throw error;
 
-         }
 
-       } else if(altName.type === 8) {
 
-         // handle OID
 
-         if(altName.oid) {
 
-           value = asn1.oidToDer(asn1.oidToDer(altName.oid));
 
-         } else {
 
-           // deprecated ... convert value to OID
 
-           value = asn1.oidToDer(value);
 
-         }
 
-       }
 
-       fullNameGeneralNames.value.push(asn1.create(
 
-         asn1.Class.CONTEXT_SPECIFIC, altName.type, false,
 
-         value));
 
-     }
 
-     // Add to the parent SEQUENCE
 
-     subSeq.value.push(asn1.create(
 
-       asn1.Class.CONTEXT_SPECIFIC, 0, true, [fullNameGeneralNames]));
 
-     seq.push(subSeq);
 
-   }
 
-   // ensure value has been defined by now
 
-   if(typeof e.value === 'undefined') {
 
-     var error = new Error('Extension value not specified.');
 
-     error.extension = e;
 
-     throw error;
 
-   }
 
-   return e;
 
- }
 
- /**
 
-  * Convert signature parameters object to ASN.1
 
-  *
 
-  * @param {String} oid Signature algorithm OID
 
-  * @param params The signature parametrs object
 
-  * @return ASN.1 object representing signature parameters
 
-  */
 
- function _signatureParametersToAsn1(oid, params) {
 
-   switch(oid) {
 
-     case oids['RSASSA-PSS']:
 
-       var parts = [];
 
-       if(params.hash.algorithmOid !== undefined) {
 
-         parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
 
-           asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-               asn1.oidToDer(params.hash.algorithmOid).getBytes()),
 
-             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
 
-           ])
 
-         ]));
 
-       }
 
-       if(params.mgf.algorithmOid !== undefined) {
 
-         parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
 
-           asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-               asn1.oidToDer(params.mgf.algorithmOid).getBytes()),
 
-             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-               asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-                 asn1.oidToDer(params.mgf.hash.algorithmOid).getBytes()),
 
-               asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
 
-             ])
 
-           ])
 
-         ]));
 
-       }
 
-       if(params.saltLength !== undefined) {
 
-         parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [
 
-           asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
 
-             asn1.integerToDer(params.saltLength).getBytes())
 
-         ]));
 
-       }
 
-       return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, parts);
 
-     default:
 
-       return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '');
 
-   }
 
- }
 
- /**
 
-  * Converts a certification request's attributes to an ASN.1 set of
 
-  * CRIAttributes.
 
-  *
 
-  * @param csr certification request.
 
-  *
 
-  * @return the ASN.1 set of CRIAttributes.
 
-  */
 
- function _CRIAttributesToAsn1(csr) {
 
-   // create an empty context-specific container
 
-   var rval = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, []);
 
-   // no attributes, return empty container
 
-   if(csr.attributes.length === 0) {
 
-     return rval;
 
-   }
 
-   // each attribute has a sequence with a type and a set of values
 
-   var attrs = csr.attributes;
 
-   for(var i = 0; i < attrs.length; ++i) {
 
-     var attr = attrs[i];
 
-     var value = attr.value;
 
-     // reuse tag class for attribute value if available
 
-     var valueTagClass = asn1.Type.UTF8;
 
-     if('valueTagClass' in attr) {
 
-       valueTagClass = attr.valueTagClass;
 
-     }
 
-     if(valueTagClass === asn1.Type.UTF8) {
 
-       value = forge.util.encodeUtf8(value);
 
-     }
 
-     var valueConstructed = false;
 
-     if('valueConstructed' in attr) {
 
-       valueConstructed = attr.valueConstructed;
 
-     }
 
-     // FIXME: handle more encodings
 
-     // create a RelativeDistinguishedName set
 
-     // each value in the set is an AttributeTypeAndValue first
 
-     // containing the type (an OID) and second the value
 
-     var seq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-       // AttributeType
 
-       asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-         asn1.oidToDer(attr.type).getBytes()),
 
-       asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [
 
-         // AttributeValue
 
-         asn1.create(
 
-           asn1.Class.UNIVERSAL, valueTagClass, valueConstructed, value)
 
-       ])
 
-     ]);
 
-     rval.value.push(seq);
 
-   }
 
-   return rval;
 
- }
 
- var jan_1_1950 = new Date('1950-01-01T00:00:00Z');
 
- var jan_1_2050 = new Date('2050-01-01T00:00:00Z');
 
- /**
 
-  * Converts a Date object to ASN.1
 
-  * Handles the different format before and after 1st January 2050
 
-  *
 
-  * @param date date object.
 
-  *
 
-  * @return the ASN.1 object representing the date.
 
-  */
 
- function _dateToAsn1(date) {
 
-   if(date >= jan_1_1950 && date < jan_1_2050) {
 
-     return asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false,
 
-       asn1.dateToUtcTime(date));
 
-   } else {
 
-     return asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false,
 
-       asn1.dateToGeneralizedTime(date));
 
-   }
 
- }
 
- /**
 
-  * Gets the ASN.1 TBSCertificate part of an X.509v3 certificate.
 
-  *
 
-  * @param cert the certificate.
 
-  *
 
-  * @return the asn1 TBSCertificate.
 
-  */
 
- pki.getTBSCertificate = function(cert) {
 
-   // TBSCertificate
 
-   var notBefore = _dateToAsn1(cert.validity.notBefore);
 
-   var notAfter = _dateToAsn1(cert.validity.notAfter);
 
-   var tbs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-     // version
 
-     asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
 
-       // integer
 
-       asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
 
-         asn1.integerToDer(cert.version).getBytes())
 
-     ]),
 
-     // serialNumber
 
-     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
 
-       forge.util.hexToBytes(cert.serialNumber)),
 
-     // signature
 
-     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-       // algorithm
 
-       asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-         asn1.oidToDer(cert.siginfo.algorithmOid).getBytes()),
 
-       // parameters
 
-       _signatureParametersToAsn1(
 
-         cert.siginfo.algorithmOid, cert.siginfo.parameters)
 
-     ]),
 
-     // issuer
 
-     _dnToAsn1(cert.issuer),
 
-     // validity
 
-     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-       notBefore,
 
-       notAfter
 
-     ]),
 
-     // subject
 
-     _dnToAsn1(cert.subject),
 
-     // SubjectPublicKeyInfo
 
-     pki.publicKeyToAsn1(cert.publicKey)
 
-   ]);
 
-   if(cert.issuer.uniqueId) {
 
-     // issuerUniqueID (optional)
 
-     tbs.value.push(
 
-       asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
 
-         asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false,
 
-           // TODO: support arbitrary bit length ids
 
-           String.fromCharCode(0x00) +
 
-           cert.issuer.uniqueId
 
-         )
 
-       ])
 
-     );
 
-   }
 
-   if(cert.subject.uniqueId) {
 
-     // subjectUniqueID (optional)
 
-     tbs.value.push(
 
-       asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [
 
-         asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false,
 
-           // TODO: support arbitrary bit length ids
 
-           String.fromCharCode(0x00) +
 
-           cert.subject.uniqueId
 
-         )
 
-       ])
 
-     );
 
-   }
 
-   if(cert.extensions.length > 0) {
 
-     // extensions (optional)
 
-     tbs.value.push(pki.certificateExtensionsToAsn1(cert.extensions));
 
-   }
 
-   return tbs;
 
- };
 
- /**
 
-  * Gets the ASN.1 CertificationRequestInfo part of a
 
-  * PKCS#10 CertificationRequest.
 
-  *
 
-  * @param csr the certification request.
 
-  *
 
-  * @return the asn1 CertificationRequestInfo.
 
-  */
 
- pki.getCertificationRequestInfo = function(csr) {
 
-   // CertificationRequestInfo
 
-   var cri = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-     // version
 
-     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
 
-       asn1.integerToDer(csr.version).getBytes()),
 
-     // subject
 
-     _dnToAsn1(csr.subject),
 
-     // SubjectPublicKeyInfo
 
-     pki.publicKeyToAsn1(csr.publicKey),
 
-     // attributes
 
-     _CRIAttributesToAsn1(csr)
 
-   ]);
 
-   return cri;
 
- };
 
- /**
 
-  * Converts a DistinguishedName (subject or issuer) to an ASN.1 object.
 
-  *
 
-  * @param dn the DistinguishedName.
 
-  *
 
-  * @return the asn1 representation of a DistinguishedName.
 
-  */
 
- pki.distinguishedNameToAsn1 = function(dn) {
 
-   return _dnToAsn1(dn);
 
- };
 
- /**
 
-  * Converts an X.509v3 RSA certificate to an ASN.1 object.
 
-  *
 
-  * @param cert the certificate.
 
-  *
 
-  * @return the asn1 representation of an X.509v3 RSA certificate.
 
-  */
 
- pki.certificateToAsn1 = function(cert) {
 
-   // prefer cached TBSCertificate over generating one
 
-   var tbsCertificate = cert.tbsCertificate || pki.getTBSCertificate(cert);
 
-   // Certificate
 
-   return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-     // TBSCertificate
 
-     tbsCertificate,
 
-     // AlgorithmIdentifier (signature algorithm)
 
-     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-       // algorithm
 
-       asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-         asn1.oidToDer(cert.signatureOid).getBytes()),
 
-       // parameters
 
-       _signatureParametersToAsn1(cert.signatureOid, cert.signatureParameters)
 
-     ]),
 
-     // SignatureValue
 
-     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false,
 
-       String.fromCharCode(0x00) + cert.signature)
 
-   ]);
 
- };
 
- /**
 
-  * Converts X.509v3 certificate extensions to ASN.1.
 
-  *
 
-  * @param exts the extensions to convert.
 
-  *
 
-  * @return the extensions in ASN.1 format.
 
-  */
 
- pki.certificateExtensionsToAsn1 = function(exts) {
 
-   // create top-level extension container
 
-   var rval = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 3, true, []);
 
-   // create extension sequence (stores a sequence for each extension)
 
-   var seq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-   rval.value.push(seq);
 
-   for(var i = 0; i < exts.length; ++i) {
 
-     seq.value.push(pki.certificateExtensionToAsn1(exts[i]));
 
-   }
 
-   return rval;
 
- };
 
- /**
 
-  * Converts a single certificate extension to ASN.1.
 
-  *
 
-  * @param ext the extension to convert.
 
-  *
 
-  * @return the extension in ASN.1 format.
 
-  */
 
- pki.certificateExtensionToAsn1 = function(ext) {
 
-   // create a sequence for each extension
 
-   var extseq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
 
-   // extnID (OID)
 
-   extseq.value.push(asn1.create(
 
-     asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-     asn1.oidToDer(ext.id).getBytes()));
 
-   // critical defaults to false
 
-   if(ext.critical) {
 
-     // critical BOOLEAN DEFAULT FALSE
 
-     extseq.value.push(asn1.create(
 
-       asn1.Class.UNIVERSAL, asn1.Type.BOOLEAN, false,
 
-       String.fromCharCode(0xFF)));
 
-   }
 
-   var value = ext.value;
 
-   if(typeof ext.value !== 'string') {
 
-     // value is asn.1
 
-     value = asn1.toDer(value).getBytes();
 
-   }
 
-   // extnValue (OCTET STRING)
 
-   extseq.value.push(asn1.create(
 
-     asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, value));
 
-   return extseq;
 
- };
 
- /**
 
-  * Converts a PKCS#10 certification request to an ASN.1 object.
 
-  *
 
-  * @param csr the certification request.
 
-  *
 
-  * @return the asn1 representation of a certification request.
 
-  */
 
- pki.certificationRequestToAsn1 = function(csr) {
 
-   // prefer cached CertificationRequestInfo over generating one
 
-   var cri = csr.certificationRequestInfo ||
 
-     pki.getCertificationRequestInfo(csr);
 
-   // Certificate
 
-   return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-     // CertificationRequestInfo
 
-     cri,
 
-     // AlgorithmIdentifier (signature algorithm)
 
-     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
 
-       // algorithm
 
-       asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
 
-         asn1.oidToDer(csr.signatureOid).getBytes()),
 
-       // parameters
 
-       _signatureParametersToAsn1(csr.signatureOid, csr.signatureParameters)
 
-     ]),
 
-     // signature
 
-     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false,
 
-       String.fromCharCode(0x00) + csr.signature)
 
-   ]);
 
- };
 
- /**
 
-  * Creates a CA store.
 
-  *
 
-  * @param certs an optional array of certificate objects or PEM-formatted
 
-  *          certificate strings to add to the CA store.
 
-  *
 
-  * @return the CA store.
 
-  */
 
- pki.createCaStore = function(certs) {
 
-   // create CA store
 
-   var caStore = {
 
-     // stored certificates
 
-     certs: {}
 
-   };
 
-   /**
 
-    * Gets the certificate that issued the passed certificate or its
 
-    * 'parent'.
 
-    *
 
-    * @param cert the certificate to get the parent for.
 
-    *
 
-    * @return the parent certificate or null if none was found.
 
-    */
 
-   caStore.getIssuer = function(cert) {
 
-     var rval = getBySubject(cert.issuer);
 
-     // see if there are multiple matches
 
-     /*if(forge.util.isArray(rval)) {
 
-       // TODO: resolve multiple matches by checking
 
-       // authorityKey/subjectKey/issuerUniqueID/other identifiers, etc.
 
-       // FIXME: or alternatively do authority key mapping
 
-       // if possible (X.509v1 certs can't work?)
 
-       throw new Error('Resolving multiple issuer matches not implemented yet.');
 
-     }*/
 
-     return rval;
 
-   };
 
-   /**
 
-    * Adds a trusted certificate to the store.
 
-    *
 
-    * @param cert the certificate to add as a trusted certificate (either a
 
-    *          pki.certificate object or a PEM-formatted certificate).
 
-    */
 
-   caStore.addCertificate = function(cert) {
 
-     // convert from pem if necessary
 
-     if(typeof cert === 'string') {
 
-       cert = forge.pki.certificateFromPem(cert);
 
-     }
 
-     ensureSubjectHasHash(cert.subject);
 
-     if(!caStore.hasCertificate(cert)) { // avoid duplicate certificates in store
 
-       if(cert.subject.hash in caStore.certs) {
 
-         // subject hash already exists, append to array
 
-         var tmp = caStore.certs[cert.subject.hash];
 
-         if(!forge.util.isArray(tmp)) {
 
-           tmp = [tmp];
 
-         }
 
-         tmp.push(cert);
 
-         caStore.certs[cert.subject.hash] = tmp;
 
-       } else {
 
-         caStore.certs[cert.subject.hash] = cert;
 
-       }
 
-     }
 
-   };
 
-   /**
 
-    * Checks to see if the given certificate is in the store.
 
-    *
 
-    * @param cert the certificate to check (either a pki.certificate or a
 
-    *          PEM-formatted certificate).
 
-    *
 
-    * @return true if the certificate is in the store, false if not.
 
-    */
 
-   caStore.hasCertificate = function(cert) {
 
-     // convert from pem if necessary
 
-     if(typeof cert === 'string') {
 
-       cert = forge.pki.certificateFromPem(cert);
 
-     }
 
-     var match = getBySubject(cert.subject);
 
-     if(!match) {
 
-       return false;
 
-     }
 
-     if(!forge.util.isArray(match)) {
 
-       match = [match];
 
-     }
 
-     // compare DER-encoding of certificates
 
-     var der1 = asn1.toDer(pki.certificateToAsn1(cert)).getBytes();
 
-     for(var i = 0; i < match.length; ++i) {
 
-       var der2 = asn1.toDer(pki.certificateToAsn1(match[i])).getBytes();
 
-       if(der1 === der2) {
 
-         return true;
 
-       }
 
-     }
 
-     return false;
 
-   };
 
-   /**
 
-    * Lists all of the certificates kept in the store.
 
-    *
 
-    * @return an array of all of the pki.certificate objects in the store.
 
-    */
 
-   caStore.listAllCertificates = function() {
 
-     var certList = [];
 
-     for(var hash in caStore.certs) {
 
-       if(caStore.certs.hasOwnProperty(hash)) {
 
-         var value = caStore.certs[hash];
 
-         if(!forge.util.isArray(value)) {
 
-           certList.push(value);
 
-         } else {
 
-           for(var i = 0; i < value.length; ++i) {
 
-             certList.push(value[i]);
 
-           }
 
-         }
 
-       }
 
-     }
 
-     return certList;
 
-   };
 
-   /**
 
-    * Removes a certificate from the store.
 
-    *
 
-    * @param cert the certificate to remove (either a pki.certificate or a
 
-    *          PEM-formatted certificate).
 
-    *
 
-    * @return the certificate that was removed or null if the certificate
 
-    *           wasn't in store.
 
-    */
 
-   caStore.removeCertificate = function(cert) {
 
-     var result;
 
-     // convert from pem if necessary
 
-     if(typeof cert === 'string') {
 
-       cert = forge.pki.certificateFromPem(cert);
 
-     }
 
-     ensureSubjectHasHash(cert.subject);
 
-     if(!caStore.hasCertificate(cert)) {
 
-       return null;
 
-     }
 
-     var match = getBySubject(cert.subject);
 
-     if(!forge.util.isArray(match)) {
 
-       result = caStore.certs[cert.subject.hash];
 
-       delete caStore.certs[cert.subject.hash];
 
-       return result;
 
-     }
 
-     // compare DER-encoding of certificates
 
-     var der1 = asn1.toDer(pki.certificateToAsn1(cert)).getBytes();
 
-     for(var i = 0; i < match.length; ++i) {
 
-       var der2 = asn1.toDer(pki.certificateToAsn1(match[i])).getBytes();
 
-       if(der1 === der2) {
 
-         result = match[i];
 
-         match.splice(i, 1);
 
-       }
 
-     }
 
-     if(match.length === 0) {
 
-       delete caStore.certs[cert.subject.hash];
 
-     }
 
-     return result;
 
-   };
 
-   function getBySubject(subject) {
 
-     ensureSubjectHasHash(subject);
 
-     return caStore.certs[subject.hash] || null;
 
-   }
 
-   function ensureSubjectHasHash(subject) {
 
-     // produce subject hash if it doesn't exist
 
-     if(!subject.hash) {
 
-       var md = forge.md.sha1.create();
 
-       subject.attributes = pki.RDNAttributesAsArray(_dnToAsn1(subject), md);
 
-       subject.hash = md.digest().toHex();
 
-     }
 
-   }
 
-   // auto-add passed in certs
 
-   if(certs) {
 
-     // parse PEM-formatted certificates as necessary
 
-     for(var i = 0; i < certs.length; ++i) {
 
-       var cert = certs[i];
 
-       caStore.addCertificate(cert);
 
-     }
 
-   }
 
-   return caStore;
 
- };
 
- /**
 
-  * Certificate verification errors, based on TLS.
 
-  */
 
- pki.certificateError = {
 
-   bad_certificate: 'forge.pki.BadCertificate',
 
-   unsupported_certificate: 'forge.pki.UnsupportedCertificate',
 
-   certificate_revoked: 'forge.pki.CertificateRevoked',
 
-   certificate_expired: 'forge.pki.CertificateExpired',
 
-   certificate_unknown: 'forge.pki.CertificateUnknown',
 
-   unknown_ca: 'forge.pki.UnknownCertificateAuthority'
 
- };
 
- /**
 
-  * Verifies a certificate chain against the given Certificate Authority store
 
-  * with an optional custom verify callback.
 
-  *
 
-  * @param caStore a certificate store to verify against.
 
-  * @param chain the certificate chain to verify, with the root or highest
 
-  *          authority at the end (an array of certificates).
 
-  * @param options a callback to be called for every certificate in the chain or
 
-  *                  an object with:
 
-  *                  verify a callback to be called for every certificate in the
 
-  *                    chain
 
-  *                  validityCheckDate the date against which the certificate
 
-  *                    validity period should be checked. Pass null to not check
 
-  *                    the validity period. By default, the current date is used.
 
-  *
 
-  * The verify callback has the following signature:
 
-  *
 
-  * verified - Set to true if certificate was verified, otherwise the
 
-  *   pki.certificateError for why the certificate failed.
 
-  * depth - The current index in the chain, where 0 is the end point's cert.
 
-  * certs - The certificate chain, *NOTE* an empty chain indicates an anonymous
 
-  *   end point.
 
-  *
 
-  * The function returns true on success and on failure either the appropriate
 
-  * pki.certificateError or an object with 'error' set to the appropriate
 
-  * pki.certificateError and 'message' set to a custom error message.
 
-  *
 
-  * @return true if successful, error thrown if not.
 
-  */
 
- pki.verifyCertificateChain = function(caStore, chain, options) {
 
-   /* From: RFC3280 - Internet X.509 Public Key Infrastructure Certificate
 
-     Section 6: Certification Path Validation
 
-     See inline parentheticals related to this particular implementation.
 
-     The primary goal of path validation is to verify the binding between
 
-     a subject distinguished name or a subject alternative name and subject
 
-     public key, as represented in the end entity certificate, based on the
 
-     public key of the trust anchor. This requires obtaining a sequence of
 
-     certificates that support that binding. That sequence should be provided
 
-     in the passed 'chain'. The trust anchor should be in the given CA
 
-     store. The 'end entity' certificate is the certificate provided by the
 
-     end point (typically a server) and is the first in the chain.
 
-     To meet this goal, the path validation process verifies, among other
 
-     things, that a prospective certification path (a sequence of n
 
-     certificates or a 'chain') satisfies the following conditions:
 
-     (a) for all x in {1, ..., n-1}, the subject of certificate x is
 
-           the issuer of certificate x+1;
 
-     (b) certificate 1 is issued by the trust anchor;
 
-     (c) certificate n is the certificate to be validated; and
 
-     (d) for all x in {1, ..., n}, the certificate was valid at the
 
-           time in question.
 
-     Note that here 'n' is index 0 in the chain and 1 is the last certificate
 
-     in the chain and it must be signed by a certificate in the connection's
 
-     CA store.
 
-     The path validation process also determines the set of certificate
 
-     policies that are valid for this path, based on the certificate policies
 
-     extension, policy mapping extension, policy constraints extension, and
 
-     inhibit any-policy extension.
 
-     Note: Policy mapping extension not supported (Not Required).
 
-     Note: If the certificate has an unsupported critical extension, then it
 
-     must be rejected.
 
-     Note: A certificate is self-issued if the DNs that appear in the subject
 
-     and issuer fields are identical and are not empty.
 
-     The path validation algorithm assumes the following seven inputs are
 
-     provided to the path processing logic. What this specific implementation
 
-     will use is provided parenthetically:
 
-     (a) a prospective certification path of length n (the 'chain')
 
-     (b) the current date/time: ('now').
 
-     (c) user-initial-policy-set: A set of certificate policy identifiers
 
-           naming the policies that are acceptable to the certificate user.
 
-           The user-initial-policy-set contains the special value any-policy
 
-           if the user is not concerned about certificate policy
 
-           (Not implemented. Any policy is accepted).
 
-     (d) trust anchor information, describing a CA that serves as a trust
 
-           anchor for the certification path. The trust anchor information
 
-           includes:
 
-       (1)  the trusted issuer name,
 
-       (2)  the trusted public key algorithm,
 
-       (3)  the trusted public key, and
 
-       (4)  optionally, the trusted public key parameters associated
 
-              with the public key.
 
-       (Trust anchors are provided via certificates in the CA store).
 
-       The trust anchor information may be provided to the path processing
 
-       procedure in the form of a self-signed certificate. The trusted anchor
 
-       information is trusted because it was delivered to the path processing
 
-       procedure by some trustworthy out-of-band procedure. If the trusted
 
-       public key algorithm requires parameters, then the parameters are
 
-       provided along with the trusted public key (No parameters used in this
 
-       implementation).
 
-     (e) initial-policy-mapping-inhibit, which indicates if policy mapping is
 
-           allowed in the certification path.
 
-           (Not implemented, no policy checking)
 
-     (f) initial-explicit-policy, which indicates if the path must be valid
 
-           for at least one of the certificate policies in the user-initial-
 
-           policy-set.
 
-           (Not implemented, no policy checking)
 
-     (g) initial-any-policy-inhibit, which indicates whether the
 
-           anyPolicy OID should be processed if it is included in a
 
-           certificate.
 
-           (Not implemented, so any policy is valid provided that it is
 
-           not marked as critical) */
 
-   /* Basic Path Processing:
 
-     For each certificate in the 'chain', the following is checked:
 
-     1. The certificate validity period includes the current time.
 
-     2. The certificate was signed by its parent (where the parent is either
 
-        the next in the chain or from the CA store). Allow processing to
 
-        continue to the next step if no parent is found but the certificate is
 
-        in the CA store.
 
-     3. TODO: The certificate has not been revoked.
 
-     4. The certificate issuer name matches the parent's subject name.
 
-     5. TODO: If the certificate is self-issued and not the final certificate
 
-        in the chain, skip this step, otherwise verify that the subject name
 
-        is within one of the permitted subtrees of X.500 distinguished names
 
-        and that each of the alternative names in the subjectAltName extension
 
-        (critical or non-critical) is within one of the permitted subtrees for
 
-        that name type.
 
-     6. TODO: If the certificate is self-issued and not the final certificate
 
-        in the chain, skip this step, otherwise verify that the subject name
 
-        is not within one of the excluded subtrees for X.500 distinguished
 
-        names and none of the subjectAltName extension names are excluded for
 
-        that name type.
 
-     7. The other steps in the algorithm for basic path processing involve
 
-        handling the policy extension which is not presently supported in this
 
-        implementation. Instead, if a critical policy extension is found, the
 
-        certificate is rejected as not supported.
 
-     8. If the certificate is not the first or if its the only certificate in
 
-        the chain (having no parent from the CA store or is self-signed) and it
 
-        has a critical key usage extension, verify that the keyCertSign bit is
 
-        set. If the key usage extension exists, verify that the basic
 
-        constraints extension exists. If the basic constraints extension exists,
 
-        verify that the cA flag is set. If pathLenConstraint is set, ensure that
 
-        the number of certificates that precede in the chain (come earlier
 
-        in the chain as implemented below), excluding the very first in the
 
-        chain (typically the end-entity one), isn't greater than the
 
-        pathLenConstraint. This constraint limits the number of intermediate
 
-        CAs that may appear below a CA before only end-entity certificates
 
-        may be issued. */
 
-   // if a verify callback is passed as the third parameter, package it within
 
-   // the options object. This is to support a legacy function signature that
 
-   // expected the verify callback as the third parameter.
 
-   if(typeof options === 'function') {
 
-     options = {verify: options};
 
-   }
 
-   options = options || {};
 
-   // copy cert chain references to another array to protect against changes
 
-   // in verify callback
 
-   chain = chain.slice(0);
 
-   var certs = chain.slice(0);
 
-   var validityCheckDate = options.validityCheckDate;
 
-   // if no validityCheckDate is specified, default to the current date. Make
 
-   // sure to maintain the value null because it indicates that the validity
 
-   // period should not be checked.
 
-   if(typeof validityCheckDate === 'undefined') {
 
-     validityCheckDate = new Date();
 
-   }
 
-   // verify each cert in the chain using its parent, where the parent
 
-   // is either the next in the chain or from the CA store
 
-   var first = true;
 
-   var error = null;
 
-   var depth = 0;
 
-   do {
 
-     var cert = chain.shift();
 
-     var parent = null;
 
-     var selfSigned = false;
 
-     if(validityCheckDate) {
 
-       // 1. check valid time
 
-       if(validityCheckDate < cert.validity.notBefore ||
 
-          validityCheckDate > cert.validity.notAfter) {
 
-         error = {
 
-           message: 'Certificate is not valid yet or has expired.',
 
-           error: pki.certificateError.certificate_expired,
 
-           notBefore: cert.validity.notBefore,
 
-           notAfter: cert.validity.notAfter,
 
-           // TODO: we might want to reconsider renaming 'now' to
 
-           // 'validityCheckDate' should this API be changed in the future.
 
-           now: validityCheckDate
 
-         };
 
-       }
 
-     }
 
-     // 2. verify with parent from chain or CA store
 
-     if(error === null) {
 
-       parent = chain[0] || caStore.getIssuer(cert);
 
-       if(parent === null) {
 
-         // check for self-signed cert
 
-         if(cert.isIssuer(cert)) {
 
-           selfSigned = true;
 
-           parent = cert;
 
-         }
 
-       }
 
-       if(parent) {
 
-         // FIXME: current CA store implementation might have multiple
 
-         // certificates where the issuer can't be determined from the
 
-         // certificate (happens rarely with, eg: old certificates) so normalize
 
-         // by always putting parents into an array
 
-         // TODO: there's may be an extreme degenerate case currently uncovered
 
-         // where an old intermediate certificate seems to have a matching parent
 
-         // but none of the parents actually verify ... but the intermediate
 
-         // is in the CA and it should pass this check; needs investigation
 
-         var parents = parent;
 
-         if(!forge.util.isArray(parents)) {
 
-           parents = [parents];
 
-         }
 
-         // try to verify with each possible parent (typically only one)
 
-         var verified = false;
 
-         while(!verified && parents.length > 0) {
 
-           parent = parents.shift();
 
-           try {
 
-             verified = parent.verify(cert);
 
-           } catch(ex) {
 
-             // failure to verify, don't care why, try next one
 
-           }
 
-         }
 
-         if(!verified) {
 
-           error = {
 
-             message: 'Certificate signature is invalid.',
 
-             error: pki.certificateError.bad_certificate
 
-           };
 
-         }
 
-       }
 
-       if(error === null && (!parent || selfSigned) &&
 
-         !caStore.hasCertificate(cert)) {
 
-         // no parent issuer and certificate itself is not trusted
 
-         error = {
 
-           message: 'Certificate is not trusted.',
 
-           error: pki.certificateError.unknown_ca
 
-         };
 
-       }
 
-     }
 
-     // TODO: 3. check revoked
 
-     // 4. check for matching issuer/subject
 
-     if(error === null && parent && !cert.isIssuer(parent)) {
 
-       // parent is not issuer
 
-       error = {
 
-         message: 'Certificate issuer is invalid.',
 
-         error: pki.certificateError.bad_certificate
 
-       };
 
-     }
 
-     // 5. TODO: check names with permitted names tree
 
-     // 6. TODO: check names against excluded names tree
 
-     // 7. check for unsupported critical extensions
 
-     if(error === null) {
 
-       // supported extensions
 
-       var se = {
 
-         keyUsage: true,
 
-         basicConstraints: true
 
-       };
 
-       for(var i = 0; error === null && i < cert.extensions.length; ++i) {
 
-         var ext = cert.extensions[i];
 
-         if(ext.critical && !(ext.name in se)) {
 
-           error = {
 
-             message:
 
-               'Certificate has an unsupported critical extension.',
 
-             error: pki.certificateError.unsupported_certificate
 
-           };
 
-         }
 
-       }
 
-     }
 
-     // 8. check for CA if cert is not first or is the only certificate
 
-     // remaining in chain with no parent or is self-signed
 
-     if(error === null &&
 
-       (!first || (chain.length === 0 && (!parent || selfSigned)))) {
 
-       // first check keyUsage extension and then basic constraints
 
-       var bcExt = cert.getExtension('basicConstraints');
 
-       var keyUsageExt = cert.getExtension('keyUsage');
 
-       if(keyUsageExt !== null) {
 
-         // keyCertSign must be true and there must be a basic
 
-         // constraints extension
 
-         if(!keyUsageExt.keyCertSign || bcExt === null) {
 
-           // bad certificate
 
-           error = {
 
-             message:
 
-               'Certificate keyUsage or basicConstraints conflict ' +
 
-               'or indicate that the certificate is not a CA. ' +
 
-               'If the certificate is the only one in the chain or ' +
 
-               'isn\'t the first then the certificate must be a ' +
 
-               'valid CA.',
 
-             error: pki.certificateError.bad_certificate
 
-           };
 
-         }
 
-       }
 
-       // basic constraints cA flag must be set
 
-       if(error === null && bcExt !== null && !bcExt.cA) {
 
-         // bad certificate
 
-         error = {
 
-           message:
 
-             'Certificate basicConstraints indicates the certificate ' +
 
-             'is not a CA.',
 
-           error: pki.certificateError.bad_certificate
 
-         };
 
-       }
 
-       // if error is not null and keyUsage is available, then we know it
 
-       // has keyCertSign and there is a basic constraints extension too,
 
-       // which means we can check pathLenConstraint (if it exists)
 
-       if(error === null && keyUsageExt !== null &&
 
-         'pathLenConstraint' in bcExt) {
 
-         // pathLen is the maximum # of intermediate CA certs that can be
 
-         // found between the current certificate and the end-entity (depth 0)
 
-         // certificate; this number does not include the end-entity (depth 0,
 
-         // last in the chain) even if it happens to be a CA certificate itself
 
-         var pathLen = depth - 1;
 
-         if(pathLen > bcExt.pathLenConstraint) {
 
-           // pathLenConstraint violated, bad certificate
 
-           error = {
 
-             message:
 
-               'Certificate basicConstraints pathLenConstraint violated.',
 
-             error: pki.certificateError.bad_certificate
 
-           };
 
-         }
 
-       }
 
-     }
 
-     // call application callback
 
-     var vfd = (error === null) ? true : error.error;
 
-     var ret = options.verify ? options.verify(vfd, depth, certs) : vfd;
 
-     if(ret === true) {
 
-       // clear any set error
 
-       error = null;
 
-     } else {
 
-       // if passed basic tests, set default message and alert
 
-       if(vfd === true) {
 
-         error = {
 
-           message: 'The application rejected the certificate.',
 
-           error: pki.certificateError.bad_certificate
 
-         };
 
-       }
 
-       // check for custom error info
 
-       if(ret || ret === 0) {
 
-         // set custom message and error
 
-         if(typeof ret === 'object' && !forge.util.isArray(ret)) {
 
-           if(ret.message) {
 
-             error.message = ret.message;
 
-           }
 
-           if(ret.error) {
 
-             error.error = ret.error;
 
-           }
 
-         } else if(typeof ret === 'string') {
 
-           // set custom error
 
-           error.error = ret;
 
-         }
 
-       }
 
-       // throw error
 
-       throw error;
 
-     }
 
-     // no longer first cert in chain
 
-     first = false;
 
-     ++depth;
 
-   } while(chain.length > 0);
 
-   return true;
 
- };
 
 
  |