bcrypto icon indicating copy to clipboard operation
bcrypto copied to clipboard

x509 Interface

Open pinheadmz opened this issue 5 years ago • 1 comments

This PR is WIP for implementing a user-friendly interface for generating x509 certificates. Ideally bcrypto could be used by a Handshake application to generate an RSA private key, construct and sign an x509 certificate, and export a TLSA record for use with DANE.

So far this branch fixes a few bugs in encoding/decoding x509 and asn1, uses an internal force flag to ensure recreation of optional elements, and adds fromJSON and getJSON methods to all types.

JSON output looks like this.

The JSON output is still a bit verbose, I'm open to input on what should come next, for example a fromOptions() type system to fill in some of the boiler-plate values and simplify some of the embedded objects/arrays. And of course sign and verify methods right on the certificate.

pinheadmz avatar Apr 20 '20 20:04 pinheadmz

Finally reached my goal of being able to generate key and ssl cert with bcrypto that can work on a Handshake website with TLSA.

Interface is pretty easy, could be more minimal with additional work, and only a few extensions and key types are currently available:

    // Create key pair and get JSON for pubkey
    const priv = rsa.privateKeyGenerate(2048);
    const pub = rsa.publicKeyCreate(priv);
    const pubJSON = rsa.publicKeyExport(pub);

    // Basic details, leave out optional and more complex stuff
    const json = {
      version: 2,
      serialNumber: 'deadbeef0101',
      signature: {
        algorithm: 'RSASHA256'
      },
      issuer: [],
      validity: {
        notBefore: { type: 'UTCTime', node: '2020-04-20T18:53:25Z' },
        notAfter: { type: 'UTCTime', node: '2021-04-20T18:53:25Z' }
      },
      subject: [],
      subjectPublicKeyInfo: {
        algorithm: {
          algorithm: 'RSAPublicKey'
        },
        publicKey: {
          modulus: pubJSON.n,
          publicExponent: pubJSON.e
        }
      },
      extensions: [
        {
          extnID: 'SubjectAltName',
          critical: false,
          extnValue: [
            { type: 'DNSName', node: '*.bcoin.io' },
            { type: 'DNSName', node: 'bcoin.io' }
          ]
        },
        {
          extnID: 'BasicConstraints',
          critical: false,
          extnValue: {cA: false, pathLenConstraint: 0}
        }
      ]
    };

    // Create to-be-signed certificate object
    const tbs = x509.TBSCertificate.fromJSON(json);

    // Use helper functions for the complicated details
    tbs.issuer = x509.Entity.fromJSON({
      COUNTRY: 'US',
      PROVINCE: 'CA',
      LOCALITY: 'San Francisco',
      ORGANIZATION: 'bcrypto',
      ORGANIZATIONALUNIT: 'encodings',
      COMMONNAME: 'bcoin.io',
      EMAILADDRESS: '[email protected]'
    });
    tbs.subject = x509.Entity.fromJSON({
      COUNTRY: 'US',
      PROVINCE: 'CA',
      LOCALITY: 'San Francisco',
      ORGANIZATION: 'bcrypto',
      ORGANIZATIONALUNIT: 'encodings',
      COMMONNAME: 'bcoin.io',
      EMAILADDRESS: '[email protected]'
    });

    // Serialize
    const msg = sha256.digest(tbs.encode());

    // Sign
    const sig = rsa.sign('SHA256', msg, priv);

    // Complete
    certFromJSON = new x509.Certificate();
    certFromJSON.tbsCertificate = tbs;
    certFromJSON.signatureAlgorithm.fromJSON({algorithm: 'RSASHA256'});
    certFromJSON.signature.fromJSON({bits: sig.length * 8, value: sig.toString('hex')});

pinheadmz avatar Jun 09 '20 18:06 pinheadmz