Просмотр исходного кода

add Pkcs10CertificationRequest Builder

Ugochukwu Mmaduekwe 1 день назад
Родитель
Сommit
f16430bdac

+ 2 - 0
CryptoLib.Examples/Delphi.Examples/CryptoLib.Examples.dpr

@@ -439,6 +439,8 @@ uses
   ClpAsn1Generators in '..\..\CryptoLib\src\Asn1\ClpAsn1Generators.pas',
   ClpIAsn1Generators in '..\..\CryptoLib\src\Interfaces\Asn1\ClpIAsn1Generators.pas',
   ClpPkcs10CertificationRequest in '..\..\CryptoLib\src\Pkcs\ClpPkcs10CertificationRequest.pas',
+  ClpPkcs10CertificationRequestBuilder in '..\..\CryptoLib\src\Pkcs\ClpPkcs10CertificationRequestBuilder.pas',
+  ClpIPkcs10CertificationRequestBuilder in '..\..\CryptoLib\src\Interfaces\Pkcs\ClpIPkcs10CertificationRequestBuilder.pas',
   ClpIX509Certificate in '..\..\CryptoLib\src\Interfaces\X509\ClpIX509Certificate.pas',
   ClpIX509CertificateParser in '..\..\CryptoLib\src\Interfaces\X509\ClpIX509CertificateParser.pas',
   ClpIX509CrlEntry in '..\..\CryptoLib\src\Interfaces\X509\ClpIX509CrlEntry.pas',

+ 31 - 4
CryptoLib.Examples/src/Examples/ClpCertificateExample.pas

@@ -25,6 +25,8 @@ uses
   ClpX509Generators,
   ClpIX509Asn1Objects,
   ClpX509Asn1Objects,
+  ClpIX509Asn1Generators,
+  ClpX509Asn1Generators,
   ClpAsn1SignatureFactory,
   ClpX509CrlParser,
   ClpIX509CrlParser,
@@ -32,7 +34,8 @@ uses
   ClpIX509Generators,
   ClpX509ExtensionUtilities,
   ClpSubjectPublicKeyInfoFactory,
-  ClpPkcs10CertificationRequest,
+  ClpPkcs10CertificationRequestBuilder,
+  ClpIPkcs10CertificationRequestBuilder,
   ClpIPkcs10CertificationRequest,
   ClpIOpenSslPemWriter,
   ClpOpenSslPemWriter,
@@ -187,13 +190,37 @@ end;
 function TCertificateExample.CreateCertRequestPem(const AKeyPair: IAsymmetricCipherKeyPair;
   const ASubject: IX509Name; const ASignatureAlgorithm: String): TCertRequestPem;
 var
-  LSignatureFactory: ISignatureFactory;
+  LBuilder: IPkcs10CertificationRequestBuilder;
   LReq: IPkcs10CertificationRequest;
+  LDnsName: IGeneralName;
+  LSanNames: IGeneralNames;
+  LExtGen: IX509ExtensionsGenerator;
+  LExtensions: IX509Extensions;
   LKeyStream, LReqStream: TStringStream;
   LWriter: IOpenSslPemWriter;
 begin
-  LSignatureFactory := TAsn1SignatureFactory.Create(ASignatureAlgorithm, AKeyPair.Private, nil);
-  LReq := TPkcs10CertificationRequest.Create(LSignatureFactory, ASubject, AKeyPair.Public, nil) as IPkcs10CertificationRequest;
+  LDnsName := TGeneralName.Create(TGeneralName.DnsName, 'cryptolib4pascal.example.com');
+  LSanNames := TGeneralNames.Create(LDnsName);
+
+  // Build some extensions via TX509ExtensionsGenerator for AddExtensions demo
+  LExtGen := TX509ExtensionsGenerator.Create();
+  LExtGen.AddExtension(TX509Extensions.BasicConstraints, True, TBasicConstraints.Create(False) as IBasicConstraints);
+  LExtGen.AddExtension(TX509Extensions.KeyUsage, True,
+    TKeyUsage.Create(TKeyUsage.DigitalSignature or TKeyUsage.KeyEncipherment) as IKeyUsage);
+  LExtensions := LExtGen.Generate();
+
+  LBuilder := TPkcs10CertificationRequestBuilder.Create();
+  LReq := LBuilder
+    .SetSubject(ASubject)
+    .SetKeyPair(AKeyPair)
+    .SetSignatureAlgorithm(ASignatureAlgorithm)
+    // Bulk: add BasicConstraints + KeyUsage from pre-built IX509Extensions
+    .AddExtensions(LExtensions)
+    // Generic: add SubjectAlternativeName via AddExtension(OID, critical, value)
+    .AddExtension(TX509Extensions.SubjectAlternativeName, False, LSanNames)
+    // Convenience: SubjectKeyIdentifier computed from public key
+    .AddSubjectKeyIdentifier(False)
+    .Build();
 
   LKeyStream := TStringStream.Create('', TEncoding.ASCII);
   try

+ 2 - 0
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -450,6 +450,8 @@ uses
   ClpAsn1Generators in '..\..\CryptoLib\src\Asn1\ClpAsn1Generators.pas',
   ClpIAsn1Generators in '..\..\CryptoLib\src\Interfaces\Asn1\ClpIAsn1Generators.pas',
   ClpPkcs10CertificationRequest in '..\..\CryptoLib\src\Pkcs\ClpPkcs10CertificationRequest.pas',
+  ClpPkcs10CertificationRequestBuilder in '..\..\CryptoLib\src\Pkcs\ClpPkcs10CertificationRequestBuilder.pas',
+  ClpIPkcs10CertificationRequestBuilder in '..\..\CryptoLib\src\Interfaces\Pkcs\ClpIPkcs10CertificationRequestBuilder.pas',
   ClpIX509Certificate in '..\..\CryptoLib\src\Interfaces\X509\ClpIX509Certificate.pas',
   ClpIX509CertificateParser in '..\..\CryptoLib\src\Interfaces\X509\ClpIX509CertificateParser.pas',
   ClpIX509CrlEntry in '..\..\CryptoLib\src\Interfaces\X509\ClpIX509CrlEntry.pas',

+ 0 - 3
CryptoLib/src/Asn1/Cms/ClpCmsParsers.pas

@@ -26,13 +26,10 @@ uses
   ClpAsn1Tags,
   ClpAsn1Objects,
   ClpAsn1Utilities,
-  ClpAsn1Parsers,
   ClpIAsn1Objects,
   ClpIAsn1Core,
   ClpIAsn1Parsers,
   ClpICmsParsers,
-  ClpICmsAsn1Objects,
-  ClpCmsAsn1Objects,
   ClpPlatformUtilities,
   ClpCryptoLibTypes;
 

+ 0 - 1
CryptoLib/src/Crypto/Signers/ClpDsaDigestSigner.pas

@@ -30,7 +30,6 @@ uses
   ClpParameterUtilities,
   ClpStandardDsaEncoding,
   ClpIDsaEncoding,
-  ClpIStandardDsaEncoding,
   ClpIAsymmetricKeyParameter,
   ClpICipherParameters,
   ClpISigner,

+ 0 - 1
CryptoLib/src/Crypto/Signers/ClpSignerUtilities.pas

@@ -61,7 +61,6 @@ uses
   ClpISecureRandom,
   ClpIAsn1Objects,
   ClpPlainDsaEncoding,
-  ClpIPlainDsaEncoding,
   ClpRsaDigestSigner,
   ClpPssSigner,
   ClpGenericSigner,

+ 0 - 1
CryptoLib/src/Interfaces/Asn1/Pkcs/ClpIPkcsAsn1Objects.pas

@@ -25,7 +25,6 @@ uses
   ClpIAsn1Objects,
   ClpIAsn1Core,
   ClpIX509Asn1Objects,
-  ClpBigInteger,
   ClpCryptoLibTypes;
 
 type

+ 128 - 0
CryptoLib/src/Interfaces/Pkcs/ClpIPkcs10CertificationRequestBuilder.pas

@@ -0,0 +1,128 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpIPkcs10CertificationRequestBuilder;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIAsn1Objects,
+  ClpIAsn1Core,
+  ClpIX509Asn1Objects,
+  ClpIPkcsAsn1Objects,
+  ClpIPkcs10CertificationRequest,
+  ClpIAsymmetricCipherKeyPair,
+  ClpCryptoLibTypes;
+
+type
+  /// <summary>
+  /// Fluent builder for PKCS#10 Certification Requests (CSRs).
+  /// Wraps the boilerplate of creating extensions, attributes, and calling
+  /// TPkcs10CertificationRequest constructors.
+  /// </summary>
+  IPkcs10CertificationRequestBuilder = interface(IInterface)
+    ['{0E5C1612-BEFE-4A4D-AD68-C134254411CE}']
+
+    /// <summary>
+    /// Set the subject distinguished name for the CSR. Required.
+    /// </summary>
+    function SetSubject(const ASubject: IX509Name): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Set the key pair (public key for the CSR, private key for signing). Required.
+    /// </summary>
+    function SetKeyPair(const AKeyPair: IAsymmetricCipherKeyPair): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Set the signature algorithm name (e.g. 'SHA256withRSA', 'SHA256withECDSA'). Required.
+    /// </summary>
+    function SetSignatureAlgorithm(const AAlgorithm: String): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Add a single arbitrary X509 extension by OID and ASN.1 value.
+    /// </summary>
+    function AddExtension(const AOid: IDerObjectIdentifier; ACritical: Boolean;
+      const AValue: IAsn1Encodable): IPkcs10CertificationRequestBuilder; overload;
+
+    /// <summary>
+    /// Add a single arbitrary X509 extension by OID and raw DER-encoded bytes.
+    /// </summary>
+    function AddExtension(const AOid: IDerObjectIdentifier; ACritical: Boolean;
+      const AExtValue: TCryptoLibByteArray): IPkcs10CertificationRequestBuilder; overload;
+
+    /// <summary>
+    /// Bulk-add all extensions from a pre-built IX509Extensions object.
+    /// </summary>
+    function AddExtensions(const AExtensions: IX509Extensions): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Add a BasicConstraints extension.
+    /// </summary>
+    function AddBasicConstraints(ACritical: Boolean; AIsCA: Boolean): IPkcs10CertificationRequestBuilder; overload;
+
+    /// <summary>
+    /// Add a BasicConstraints extension with a path length constraint (implies CA=True).
+    /// </summary>
+    function AddBasicConstraints(ACritical: Boolean; APathLenConstraint: Int32): IPkcs10CertificationRequestBuilder; overload;
+
+    /// <summary>
+    /// Add a KeyUsage extension.
+    /// </summary>
+    function AddKeyUsage(ACritical: Boolean; AUsage: Int32): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Add a SubjectAlternativeName extension.
+    /// </summary>
+    function AddSubjectAlternativeName(ACritical: Boolean;
+      const ANames: IGeneralNames): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Add an ExtendedKeyUsage extension from an array of key purpose OIDs.
+    /// </summary>
+    function AddExtendedKeyUsage(ACritical: Boolean;
+      const AUsages: TCryptoLibGenericArray<IDerObjectIdentifier>): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Add a SubjectKeyIdentifier extension computed from the public key.
+    /// SetKeyPair must be called before this method.
+    /// </summary>
+    function AddSubjectKeyIdentifier(ACritical: Boolean): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Add a raw PKCS attribute (for non-extension attributes).
+    /// </summary>
+    function AddAttribute(const AAttribute: IAttributePkcs): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Reset the builder to its initial state, clearing subject, key pair,
+    /// signature algorithm, extensions and attributes so it can be reused.
+    /// </summary>
+    function Reset: IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Build and return the signed PKCS#10 Certification Request.
+    /// Subject, KeyPair, and SignatureAlgorithm must all be set before calling Build.
+    /// </summary>
+    function Build: IPkcs10CertificationRequest;
+
+  end;
+
+implementation
+
+end.

+ 0 - 1
CryptoLib/src/OpenSsl/ClpOpenSslPemReader.pas

@@ -62,7 +62,6 @@ uses
   ClpIDsaParameters,
   ClpX9ObjectIdentifiers,
   ClpECGenerators,
-  ClpIECGenerators,
   ClpIECParameters,
   ClpIX509Asn1Objects,
   ClpStringUtilities,

+ 9 - 1
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk

@@ -25,7 +25,7 @@
  Acknowledgements: 
 Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the development of this library "/>
     <Version Major="3" Minor="3"/>
-    <Files Count="488">
+    <Files Count="489">
       <Item1>
         <Filename Value="..\..\Asn1\ClpOidTokenizer.pas"/>
         <UnitName Value="ClpOidTokenizer"/>
@@ -1911,6 +1911,10 @@ Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the devel
         <Filename Value="..\..\Asn1\Cms\ClpCmsObjectIdentifiers.pas"/>
         <UnitName Value="ClpCmsObjectIdentifiers"/>
       </Item471>
+      <Item472>
+        <Filename Value="..\..\Pkcs\ClpPkcs10CertificationRequestBuilder.pas"/>
+        <UnitName Value="ClpPkcs10CertificationRequestBuilder"/>
+      </Item472>
       <Item473>
         <Filename Value="..\..\Asn1\Cms\ClpCmsParsers.pas"/>
         <UnitName Value="ClpCmsParsers"/>
@@ -1975,6 +1979,10 @@ Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the devel
         <Filename Value="..\..\Pem\ClpPemWriter.pas"/>
         <UnitName Value="ClpPemWriter"/>
       </Item488>
+      <Item489>
+        <Filename Value="..\..\Interfaces\Pkcs\ClpIPkcs10CertificationRequestBuilder.pas"/>
+        <UnitName Value="ClpIPkcs10CertificationRequestBuilder"/>
+      </Item489>
     </Files>
     <CompatibilityMode Value="True"/>
     <RequiredPkgs Count="3">

+ 7 - 6
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas

@@ -155,12 +155,13 @@ uses
   ClpAttributeCertificateHolder, ClpX509Utilities, ClpX509Generators, 
   ClpDeltaCertificateTool, ClpX509Attribute, ClpX509ExtensionBase, 
   ClpX509ExtensionUtilities, ClpDevRandomReader, ClpBaseRandomProvider, 
-  ClpCmsAsn1Objects, ClpCmsObjectIdentifiers, ClpCmsParsers, 
-  ClpICmsAsn1Objects, ClpICmsParsers, ClpOpenSslMiscPemGenerator, 
-  ClpOpenSslPemReader, ClpOpenSslPemWriter, ClpIOpenSslPemReader, 
-  ClpIOpenSslPemWriter, ClpPkcsDHAsn1Objects, ClpIPkcsDHAsn1Objects, 
-  ClpIPemParser, ClpIPemReader, ClpIPemWriter, ClpPemParser, ClpPemReader, 
-  ClpPemWriter;
+  ClpCmsAsn1Objects, ClpCmsObjectIdentifiers, 
+  ClpPkcs10CertificationRequestBuilder, ClpCmsParsers, ClpICmsAsn1Objects, 
+  ClpICmsParsers, ClpOpenSslMiscPemGenerator, ClpOpenSslPemReader, 
+  ClpOpenSslPemWriter, ClpIOpenSslPemReader, ClpIOpenSslPemWriter, 
+  ClpPkcsDHAsn1Objects, ClpIPkcsDHAsn1Objects, ClpIPemParser, ClpIPemReader, 
+  ClpIPemWriter, ClpPemParser, ClpPemReader, ClpPemWriter, 
+  ClpIPkcs10CertificationRequestBuilder;
 
 implementation
 

+ 1 - 6
CryptoLib/src/Pem/ClpPemObjects.pas

@@ -24,16 +24,11 @@ interface
 uses
   SysUtils,
   Classes,
-  Generics.Collections,
   ClpAsn1Core,
-  ClpIAsn1Core,
   ClpIPemObjects,
   ClpCryptoLibTypes,
-  ClpEncoders,
   ClpStringUtilities,
-  ClpAsn1Objects,
-  ClpIAsn1Objects,
-  ClpCollectionUtilities;
+  ClpAsn1Objects;
 
 type
   /// <summary>

+ 0 - 1
CryptoLib/src/Pem/ClpPemWriter.pas

@@ -28,7 +28,6 @@ uses
   ClpIPemObjects,
   ClpCryptoLibTypes,
   ClpEncoders,
-  ClpStringUtilities,
   ClpConverters;
 
 type

+ 251 - 0
CryptoLib/src/Pkcs/ClpPkcs10CertificationRequestBuilder.pas

@@ -0,0 +1,251 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpPkcs10CertificationRequestBuilder;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  Generics.Collections,
+  ClpAsn1Objects,
+  ClpIAsn1Objects,
+  ClpIAsn1Core,
+  ClpAsn1Core,
+  ClpIPkcsAsn1Objects,
+  ClpPkcsAsn1Objects,
+  ClpPkcsObjectIdentifiers,
+  ClpX509Asn1Objects,
+  ClpIX509Asn1Objects,
+  ClpIX509Asn1Generators,
+  ClpX509Asn1Generators,
+  ClpX509ExtensionUtilities,
+  ClpSubjectPublicKeyInfoFactory,
+  ClpAsn1SignatureFactory,
+  ClpISignatureFactory,
+  ClpPkcs10CertificationRequest,
+  ClpIPkcs10CertificationRequest,
+  ClpIPkcs10CertificationRequestBuilder,
+  ClpIAsymmetricCipherKeyPair,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SSubjectNotSet = 'Subject must be set before calling Build';
+  SKeyPairNotSet = 'KeyPair must be set before calling Build';
+  SSignatureAlgorithmNotSet = 'SignatureAlgorithm must be set before calling Build';
+  SKeyPairRequiredForSKI = 'KeyPair must be set before calling AddSubjectKeyIdentifier';
+
+type
+  /// <summary>
+  /// Fluent builder for PKCS#10 Certification Requests (CSRs).
+  /// </summary>
+  TPkcs10CertificationRequestBuilder = class(TInterfacedObject, IPkcs10CertificationRequestBuilder)
+
+  strict private
+  var
+    FSubject: IX509Name;
+    FKeyPair: IAsymmetricCipherKeyPair;
+    FSignatureAlgorithm: String;
+    FExtGen: IX509ExtensionsGenerator;
+    FAttributes: TList<IAttributePkcs>;
+
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function SetSubject(const ASubject: IX509Name): IPkcs10CertificationRequestBuilder;
+    function SetKeyPair(const AKeyPair: IAsymmetricCipherKeyPair): IPkcs10CertificationRequestBuilder;
+    function SetSignatureAlgorithm(const AAlgorithm: String): IPkcs10CertificationRequestBuilder;
+
+    function AddExtension(const AOid: IDerObjectIdentifier; ACritical: Boolean;
+      const AValue: IAsn1Encodable): IPkcs10CertificationRequestBuilder; overload;
+    function AddExtension(const AOid: IDerObjectIdentifier; ACritical: Boolean;
+      const AExtValue: TCryptoLibByteArray): IPkcs10CertificationRequestBuilder; overload;
+    function AddExtensions(const AExtensions: IX509Extensions): IPkcs10CertificationRequestBuilder;
+
+    function AddBasicConstraints(ACritical: Boolean; AIsCA: Boolean): IPkcs10CertificationRequestBuilder; overload;
+    function AddBasicConstraints(ACritical: Boolean; APathLenConstraint: Int32): IPkcs10CertificationRequestBuilder; overload;
+    function AddKeyUsage(ACritical: Boolean; AUsage: Int32): IPkcs10CertificationRequestBuilder;
+    function AddSubjectAlternativeName(ACritical: Boolean;
+      const ANames: IGeneralNames): IPkcs10CertificationRequestBuilder;
+    function AddExtendedKeyUsage(ACritical: Boolean;
+      const AUsages: TCryptoLibGenericArray<IDerObjectIdentifier>): IPkcs10CertificationRequestBuilder;
+    function AddSubjectKeyIdentifier(ACritical: Boolean): IPkcs10CertificationRequestBuilder;
+
+    function AddAttribute(const AAttribute: IAttributePkcs): IPkcs10CertificationRequestBuilder;
+
+    function Reset: IPkcs10CertificationRequestBuilder;
+    function Build: IPkcs10CertificationRequest;
+
+  end;
+
+implementation
+
+{ TPkcs10CertificationRequestBuilder }
+
+constructor TPkcs10CertificationRequestBuilder.Create;
+begin
+  inherited Create;
+  FExtGen := TX509ExtensionsGenerator.Create();
+  FAttributes := TList<IAttributePkcs>.Create;
+end;
+
+destructor TPkcs10CertificationRequestBuilder.Destroy;
+begin
+  FAttributes.Free;
+  inherited Destroy;
+end;
+
+function TPkcs10CertificationRequestBuilder.SetSubject(const ASubject: IX509Name): IPkcs10CertificationRequestBuilder;
+begin
+  FSubject := ASubject;
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.SetKeyPair(const AKeyPair: IAsymmetricCipherKeyPair): IPkcs10CertificationRequestBuilder;
+begin
+  FKeyPair := AKeyPair;
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.SetSignatureAlgorithm(const AAlgorithm: String): IPkcs10CertificationRequestBuilder;
+begin
+  FSignatureAlgorithm := AAlgorithm;
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddExtension(const AOid: IDerObjectIdentifier;
+  ACritical: Boolean; const AValue: IAsn1Encodable): IPkcs10CertificationRequestBuilder;
+begin
+  FExtGen.AddExtension(AOid, ACritical, AValue);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddExtension(const AOid: IDerObjectIdentifier;
+  ACritical: Boolean; const AExtValue: TCryptoLibByteArray): IPkcs10CertificationRequestBuilder;
+begin
+  FExtGen.AddExtension(AOid, ACritical, AExtValue);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddExtensions(const AExtensions: IX509Extensions): IPkcs10CertificationRequestBuilder;
+begin
+  FExtGen.AddExtensions(AExtensions);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddBasicConstraints(ACritical: Boolean;
+  AIsCA: Boolean): IPkcs10CertificationRequestBuilder;
+begin
+  FExtGen.AddExtension(TX509Extensions.BasicConstraints, ACritical, TBasicConstraints.Create(AIsCA) as IBasicConstraints);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddBasicConstraints(ACritical: Boolean;
+  APathLenConstraint: Int32): IPkcs10CertificationRequestBuilder;
+begin
+  FExtGen.AddExtension(TX509Extensions.BasicConstraints, ACritical, TBasicConstraints.Create(APathLenConstraint) as IBasicConstraints);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddKeyUsage(ACritical: Boolean;
+  AUsage: Int32): IPkcs10CertificationRequestBuilder;
+begin
+  FExtGen.AddExtension(TX509Extensions.KeyUsage, ACritical, TKeyUsage.Create(AUsage) as IKeyUsage);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddSubjectAlternativeName(ACritical: Boolean;
+  const ANames: IGeneralNames): IPkcs10CertificationRequestBuilder;
+begin
+  FExtGen.AddExtension(TX509Extensions.SubjectAlternativeName, ACritical, ANames);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddExtendedKeyUsage(ACritical: Boolean;
+  const AUsages: TCryptoLibGenericArray<IDerObjectIdentifier>): IPkcs10CertificationRequestBuilder;
+begin
+  FExtGen.AddExtension(TX509Extensions.ExtendedKeyUsage, ACritical, TExtendedKeyUsage.Create(AUsages) as IExtendedKeyUsage);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddSubjectKeyIdentifier(ACritical: Boolean): IPkcs10CertificationRequestBuilder;
+var
+  LSpki: ISubjectPublicKeyInfo;
+begin
+  if FKeyPair = nil then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SKeyPairRequiredForSKI);
+  LSpki := TSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(FKeyPair.Public);
+  FExtGen.AddExtension(TX509Extensions.SubjectKeyIdentifier, ACritical,
+    TX509ExtensionUtilities.CreateSubjectKeyIdentifier(LSpki));
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.AddAttribute(const AAttribute: IAttributePkcs): IPkcs10CertificationRequestBuilder;
+begin
+  FAttributes.Add(AAttribute);
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.Reset: IPkcs10CertificationRequestBuilder;
+begin
+  FSubject := nil;
+  FKeyPair := nil;
+  FSignatureAlgorithm := '';
+  FExtGen.Reset;
+  FAttributes.Clear;
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilder.Build: IPkcs10CertificationRequest;
+var
+  LSignatureFactory: ISignatureFactory;
+  LAttrVec: IAsn1EncodableVector;
+  LExtAttr: IAttributePkcs;
+  LAttributes: IAsn1Set;
+  LItem: IAttributePkcs;
+begin
+  if FSubject = nil then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SSubjectNotSet);
+  if FKeyPair = nil then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SKeyPairNotSet);
+  if FSignatureAlgorithm = '' then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SSignatureAlgorithmNotSet);
+
+  LAttrVec := TAsn1EncodableVector.Create;
+
+  if not FExtGen.IsEmpty then
+  begin
+    LExtAttr := TAttributePkcs.Create(TPkcsObjectIdentifiers.Pkcs9AtExtensionRequest,
+      TDerSet.Create(FExtGen.Generate()) as IDerSet);
+    LAttrVec.Add(LExtAttr);
+  end;
+
+  for LItem in FAttributes do
+    LAttrVec.Add(LItem);
+
+  if LAttrVec.Count > 0 then
+    LAttributes := TDerSet.Create(LAttrVec)
+  else
+    LAttributes := nil;
+
+  LSignatureFactory := TAsn1SignatureFactory.Create(FSignatureAlgorithm, FKeyPair.Private, nil);
+  Result := TPkcs10CertificationRequest.Create(LSignatureFactory, FSubject, FKeyPair.Public, LAttributes);
+end;
+
+end.