digitalbazaar / forge

A native implementation of TLS in Javascript and tools to write crypto-based and network-heavy webapps
https://digitalbazaar.com/
Other
5.01k stars 767 forks source link

When creating self-signed certificate how can I add subjectAltName #1080

Open vricosti opened 1 month ago

vricosti commented 1 month ago

Hi,

I am using forge to create a self-signed certificate but I would like to add subjectAltName property, in openssl we can do it by passing the -addext "subjectAltName = IP.1:1.2.3.4".

static async generateFull(host, name, country, state, locality, organisation, OU){

        if (jsEnv.isReactNative) {
            console.log('react-native detected => patch to use react-native-modpow');

            const modPowModule = await import('react-native-modpow');
            const modPow = modPowModule.default;

            forge.jsbn.BigInteger.prototype.modPow = function nativeModPow(e, m) {
                const result = modPow({
                    target: this.toString(16),
                    value: e.toString(16),
                    modifier: m.toString(16)
                });

                return new forge.jsbn.BigInteger(result, 16);
            };
        }

        console.log('Entering generateFull');
        let keys = forge.pki.rsa.generateKeyPair(2048);
        console.log('after generateKeyPair with keys: ', keys);
        let cert = forge.pki.createCertificate();
        console.log('after createCertificate with cert: ', cert);
        cert.publicKey = keys.publicKey;
        cert.serialNumber = '01' + forge.util.bytesToHex(forge.random.getBytesSync(19));
        cert.validity.notBefore = new Date();
        let date = new Date();
        date.setUTCFullYear(2099);
        cert.validity.notAfter = date;

        let attributes = [
            {name: 'commonName', value: name},
            {name: 'countryName', value: country},
            {shortName: 'ST', value: state},
            {name: 'localityName', value: locality},
            {name: 'organizationName', value: organisation},
            {shortName: 'OU', value: OU}
        ];
        cert.setSubject(attributes);
        cert.sign(keys.privateKey, forge.md.sha256.create());

        return {
            cert : forge.pki.certificateToPem(cert),
            key : forge.pki.privateKeyToPem(keys.privateKey),
        }
    }

Do I need to add inside attributes ?

Shahanshah-TA commented 1 week ago

Try like this

import forge from 'node-forge';
import modPow from 'react-native-modpow';

forge.jsbn.BigInteger.prototype.modPow = function nativeModPow(e, m) {
  const result = modPow({
    target: this.toString(16),
    value: e.toString(16),
    modifier: m.toString(16),
  });

  return new forge.jsbn.BigInteger(result, 16);
};

export async function createX509Certificate(subjectName) {
  return new Promise((resolve, reject) => {
    // Create a new key pair
    const certificateKey = forge.pki.rsa.generateKeyPair({
      bits: 2048,
      e: 65537,
    });

    const csr = forge.pki.createCertificationRequest();
    csr.publicKey = certificateKey.publicKey;

    // Set subject with just the Common Name
    csr.setSubject([{name: 'commonName', value: `${subjectName}`}]);

    // Add key usage extension
    csr.addAttribute({
      name: 'extensionRequest',
      extensions: [
        {
          name: 'keyUsage',
          digitalSignature: true,
          keyEncipherment: true,
        },
      ],
    });

    // Add basic constraints extension
    csr.addAttribute({
      name: 'extensionRequest',
      extensions: [
        {
          name: 'basicConstraints',
          cA: false,
        },
      ],
    });

    // Add extended key usage extension
    csr.addAttribute({
      name: 'extensionRequest',
      extensions: [
        {
          name: 'extKeyUsage',
          serverAuth: true,
          clientAuth: true,
        },
      ],
    });

    // Sign the CSR with the private key
    csr.sign(certificateKey.privateKey);

    // Convert the CSR to PEM format
    let certificate = forge.pki.certificationRequestToPem(csr);
    // remove all the line break
    // certificate = certificate.replace(/(\r\n|\n|\r)/gm, '');
    // // remove -----BEGIN CERTIFICATE REQUEST----- & -----END CERTIFICATE REQUEST-----
    // certificate = certificate.substring(35, certificate.length - 33);

    console.log({certificate, certificateKey});
    resolve({certificate, certificateKey});
  });
}