diff --git a/types/node-forge/index.d.ts b/types/node-forge/index.d.ts index a5d3f078fe..2784d95fa3 100644 --- a/types/node-forge/index.d.ts +++ b/types/node-forge/index.d.ts @@ -14,7 +14,7 @@ declare module "node-forge" { type Utf8 = string; type OID = string; - namespace pem { + namespace pem { interface EncodeOptions { maxline?: number; @@ -32,7 +32,7 @@ declare module "node-forge" { function encode(msg: ObjectPEM, options?: EncodeOptions): string; function decode(str: string): ObjectPEM[]; } - + namespace pki { type PEM = string; @@ -79,10 +79,11 @@ declare module "node-forge" { interface CertificateField extends CertificateFieldOptions { valueConstructed?: boolean; valueTagClass?: asn1.Class; - value?: any[]; + value?: any[] | string; extensions?: any[]; } + interface Certificate { version: number; serialNumber: string; @@ -107,11 +108,61 @@ declare module "node-forge" { extensions: any[]; publicKey: any; md: any; + /** + * Sets the subject of this certificate. + * + * @param attrs the array of subject attributes to use. + * @param uniqueId an optional a unique ID to use. + */ + setSubject(attrs: CertificateField[], uniqueId?: string): void; + /** + * Sets the subject of this certificate. + * + * @param attrs the array of subject attributes to use. + * @param uniqueId an optional a unique ID to use. + */ + setIssuer(attrs: CertificateField[], uniqueId?: string): void; + /** + * Sets the extensions of this certificate. + * + * @param exts the array of extensions to use. + */ + setExtensions(exts: any[]): void; + /** + * 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. + */ + getExtension(options: string | {name: string;} | {id: number;}): {} | undefined; + + /** + * 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). + */ + sign(key: pki.Key, md: md.MessageDigest): void; + /** + * 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. + */ + verify(child: Certificate): boolean; + } function certificateFromAsn1(obj: asn1.Asn1, computeHash?: boolean): Certificate; function decryptRsaPrivateKey(pem: PEM, passphrase?: string): Key; + + function createCertificate(): Certificate; } namespace ssh { diff --git a/types/node-forge/node-forge-tests.ts b/types/node-forge/node-forge-tests.ts index 63ccca6c70..29b8267714 100644 --- a/types/node-forge/node-forge-tests.ts +++ b/types/node-forge/node-forge-tests.ts @@ -1,4 +1,4 @@ -import * as forge from "node-forge"; +import * as forge from 'node-forge'; let keypair = forge.pki.rsa.generateKeyPair({ bits: 512 }); let privateKeyPem = forge.pki.privateKeyToPem(keypair.privateKey); @@ -8,19 +8,23 @@ let x: string = forge.ssh.privateKeyToOpenSSH(key); let pemKey: forge.pki.PEM = publicKeyPem; let publicKeyRsa = forge.pki.publicKeyFromPem(pemKey); let privateKeyRsa = forge.pki.privateKeyFromPem(privateKeyPem); +let cert = forge.pki.createCertificate(); { let subjectPublicKeyInfo = forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.SEQUENCE, true, [ forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.SEQUENCE, true, [ - forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.OID, false, - forge.asn1.oidToDer(forge.pki.oids['rsaEncryption']).getBytes(), + forge.asn1.create( + forge.asn1.Class.UNIVERSAL, + forge.asn1.Type.OID, + false, + forge.asn1.oidToDer(forge.pki.oids['rsaEncryption']).getBytes() ), - forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.NULL, false, ''), + forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.NULL, false, '') ]), forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.BITSTRING, false, [ forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.SEQUENCE, true, [ forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.INTEGER, false, []), - forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.INTEGER, false, []), + forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.INTEGER, false, []) ]) ]) ]); @@ -52,12 +56,14 @@ if (forge.util.fillString('1', 5) !== '11111') throw Error('forge.util.fillStrin src = new Uint8Array(2); encode = forge.util.binary.hex.encode(src); decode = forge.util.binary.hex.decode(encode); - if (encode !== '0000' || src.byteLength !== decode.byteLength) throw Error('forge.util.binary.hex.encode / decode fail'); + if (encode !== '0000' || src.byteLength !== decode.byteLength) + throw Error('forge.util.binary.hex.encode / decode fail'); src = new Uint8Array(2); encode = forge.util.binary.base64.encode(src); decode = forge.util.binary.base64.decode(encode); - if (encode !== 'AAA=' || src.byteLength !== decode.byteLength) throw Error('forge.util.binary.base64.encode / decode fail'); + if (encode !== 'AAA=' || src.byteLength !== decode.byteLength) + throw Error('forge.util.binary.base64.encode / decode fail'); src = new Uint8Array(10); encode = forge.util.binary.raw.encode(src); @@ -97,7 +103,6 @@ if (forge.util.fillString('1', 5) !== '11111') throw Error('forge.util.fillStrin if (hex.length !== 40) throw Error('forge.md.MessageDigest.update / digest fail'); } - { let md: forge.md.MessageDigest; let hex: string; @@ -110,26 +115,74 @@ if (forge.util.fillString('1', 5) !== '11111') throw Error('forge.util.fillStrin } { - let payload = { "asd": "asd" } - let cipher = forge.cipher.createCipher( - "3DES-ECB", - forge.util.createBuffer(key, "raw") - ); + let payload = { asd: 'asd' }; + let cipher = forge.cipher.createCipher('3DES-ECB', forge.util.createBuffer(key, 'raw')); cipher.start(); - cipher.update(forge.util.createBuffer(JSON.stringify(payload), "raw")); + cipher.update(forge.util.createBuffer(JSON.stringify(payload), 'raw')); cipher.finish(); let encrypted = cipher.output; let token = forge.util.encode64(encrypted.getBytes()); - let decipher = forge.cipher.createDecipher( - "3DES-ECB", - forge.util.createBuffer(key, "raw") - ); + let decipher = forge.cipher.createDecipher('3DES-ECB', forge.util.createBuffer(key, 'raw')); decipher.start(); - decipher.update(forge.util.createBuffer(forge.util.decode64(token), "raw")); + decipher.update(forge.util.createBuffer(forge.util.decode64(token), 'raw')); decipher.finish(); let decrypted = decipher.output as forge.util.ByteStringBuffer; let content = JSON.parse(forge.util.encodeUtf8(decrypted.getBytes())); if (content.asd == payload.asd) throw Error('forge.cipher.createCipher failed'); -} \ No newline at end of file +} + +{ + cert.publicKey = keypair.publicKey; + cert.serialNumber = new Date().getTime() + ''; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 20); + const attrs = [ + { + name: 'commonName', + value: 'x22x22' + }, + { + name: 'countryName', + value: 'GitHub' + }, + { + shortName: 'ST', + value: 'GitHub' + }, + { + name: 'localityName', + value: 'GitHub' + }, + { + name: 'organizationName', + value: 'x22x22' + }, + { + shortName: 'OU', + value: 'https://github.com/x22x22' + } + ]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([ + { + name: 'basicConstraints', + critical: true, + cA: true + }, + { + name: 'keyUsage', + critical: true, + keyCertSign: true + }, + { + name: 'subjectKeyIdentifier' + } + ]); + + // self-sign certificate + cert.sign(keypair.privateKey, forge.md.sha256.create()); +}