Menu

#29 Function for adding extensions to a self signed certificate

Request
open
nobody
None
5
2023-11-12
2023-11-12
No

Hello,

for a project I needed to extend a self signed certificate with some extensions using OpenSSL version 1.1. Attached are two patches:
0001-Add-types-and-funtions-that-are-needed-fo-adding-ext.patch adds necessary types and functions for OpenSSL so extensions can be added.
0002-Add-utility-function-X509AddExtension-for-adding-ext.patch adds the utility function X509AddExtension for easing the process of adding an extension to a certificate.

When used, a function for creating a self signed certificate can look like this:

function CreateSelfSignedCert(const HostName, Country: String; const ValidDays: Integer; out Certificate, Key: RawBytestring): Boolean;
var
  pk: EVP_PKEY;
  x: PX509;
  rsa: PRSA;
  t: PASN1_UTCTIME;
  name: PX509_NAME;
  b: PBIO;
  xn, y: integer;
  s: AnsiString;
begin
  Result := True;
  pk := EvpPkeynew;
  x := X509New;
  try
    rsa := RsaGenerateKey(2048, $10001, nil, nil);
    EvpPkeyAssign(pk, EVP_PKEY_RSA, rsa);
    X509SetVersion(x, 2);
//    Asn1IntegerSet(X509getSerialNumber(x), 0);
    Asn1IntegerSet(X509getSerialNumber(x), GetTick);
    t := Asn1UtctimeNew;
    try
      X509GmtimeAdj(t, -60 * 60 *24);
      X509SetNotBefore(x, t);
      X509GmtimeAdj(t, ValidDays * 60 * 60 *24);
      X509SetNotAfter(x, t);
    finally
      Asn1UtctimeFree(t);
    end;
    X509SetPubkey(x, pk);
    Name := X509GetSubjectName(x);
    X509NameAddEntryByTxt(Name, 'C', $1001, Country, -1, -1, 0);
    X509NameAddEntryByTxt(Name, 'CN', $1001, HostName, -1, -1, 0);
    X509AddExtension(x, NID_ext_key_usage, 'serverAuth,clientAuth');
    X509AddExtension(x, NID_subject_alt_name, 'DNS:' + HostName);
    X509AddExtension(x, NID_basic_constraints, 'CA:true');

    x509SetIssuerName(x, Name);
    x509Sign(x, pk, EvpGetDigestByName('SHA256'));
    b := BioNew(BioSMem);
    try
      i2dX509Bio(b, x);
      xn := bioctrlpending(b);
      setlength(s, xn);
      y := bioread(b, s, xn);
      if y > 0 then
        setlength(s, y);
    finally
      BioFreeAll(b);
    end;
    Certificate := s;
    b := BioNew(BioSMem);
    try
      i2dPrivatekeyBio(b, pk);
      xn := bioctrlpending(b);
      setlength(s, xn);
      y := bioread(b, s, xn);
      if y > 0 then
        setlength(s, y);
    finally
      BioFreeAll(b);
    end;
    Key := s;
  finally
    X509free(x);
    EvpPkeyFree(pk);
  end;
end;

Note: X509V3_EXT_conf_nid seems to not be documented and isn't exported with OpenSSL version 3.1 (maybe earlier) anymore. The official way seems to be to use X509_EXTENSION_create_by_NID. An example on how to use that can be found on
https://github.com/openssl/openssl/issues/11706#issuecomment-623791405

Discussion


Log in to post a comment.