Преглед изворни кода

Add PKCS#10 CSR generation with ECDSA and EdDSA support

- Add AlgorithmIdentifier, SubjectPublicKeyInfo, X500Name ASN.1 types
- Implement fluent X500NameBuilder for constructing distinguished names
- Add unified CreateFromPublicKey factory for SubjectPublicKeyInfo
  supporting ECDSA and Ed25519 key types with auto-detection
- Create inheritance-based CSR builder hierarchy:
  - TPkcs10CertificationRequestBuilderBase (shared SetSubject, CreateCSR)
  - TECDSACertificationRequestBuilder (digest in constructor)
  - TEdDSACertificationRequestBuilder (Ed25519, extensible for Ed448)
- Use class var dictionary for ECDSA digest-to-OID mapping with
  TX9ObjectIdentifiers constants
- Support DER and PEM encoding output
- Add comprehensive unit tests
Ugochukwu Mmaduekwe пре 1 месец
родитељ
комит
bdd7a0abad

+ 10 - 0
CryptoLib.Samples/Delphi.Samples/UsageSamples.dpr

@@ -365,11 +365,21 @@ uses
   ClpECCompUtilities in '..\..\CryptoLib\src\Math\EC\ClpECCompUtilities.pas',
   ClpIKMac in '..\..\CryptoLib\src\Interfaces\ClpIKMac.pas',
   ClpKMac in '..\..\CryptoLib\src\Crypto\Macs\ClpKMac.pas',
+  ClpAlgorithmIdentifier in '..\..\CryptoLib\src\Asn1\X509\ClpAlgorithmIdentifier.pas',
+  ClpIAlgorithmIdentifier in '..\..\CryptoLib\src\Interfaces\ClpIAlgorithmIdentifier.pas',
+  ClpSubjectPublicKeyInfo in '..\..\CryptoLib\src\Asn1\X509\ClpSubjectPublicKeyInfo.pas',
+  ClpISubjectPublicKeyInfo in '..\..\CryptoLib\src\Interfaces\ClpISubjectPublicKeyInfo.pas',
+  ClpX500Name in '..\..\CryptoLib\src\Asn1\X509\ClpX500Name.pas',
+  ClpIX500Name in '..\..\CryptoLib\src\Interfaces\ClpIX500Name.pas',
+  ClpPkcs10CertificationRequest in '..\..\CryptoLib\src\Asn1\Pkcs\ClpPkcs10CertificationRequest.pas',
+  ClpIPkcs10CertificationRequest in '..\..\CryptoLib\src\Interfaces\ClpIPkcs10CertificationRequest.pas',
   UsageExamples in '..\src\UsageExamples.pas';
 
 begin
   try
     { TODO -oUser -cConsole Main : Insert code here }
+    TUsageExamples.GenerateCSRWithECDSA;
+    TUsageExamples.GenerateCSRWithEdDSA;
     TUsageExamples.GenerateKeyPairAndSignECDSA;
     TUsageExamples.GenerateKeyPairAndSignECSchnorr;
     TUsageExamples.GetPublicKeyFromPrivateKey;

+ 183 - 1
CryptoLib.Samples/src/UsageExamples.pas

@@ -83,7 +83,22 @@ uses
   ClpEncoders,
   // ClpSecNamedCurves,
   ClpCustomNamedCurves,
-  ClpConverters;
+  ClpConverters,
+  ClpX500Name,
+  ClpIX500Name,
+  ClpPkcs10CertificationRequest,
+  ClpIPkcs10CertificationRequest,
+  // Ed25519 support
+  ClpEd25519KeyPairGenerator,
+  ClpIEd25519KeyPairGenerator,
+  ClpEd25519KeyGenerationParameters,
+  ClpIEd25519KeyGenerationParameters,
+  ClpIEd25519PublicKeyParameters,
+  ClpIEd25519PrivateKeyParameters,
+  ClpEd25519,
+  ClpIEd25519,
+  ClpAsn1Objects,
+  ClpIAsn1Objects;
 
 type
 
@@ -163,6 +178,16 @@ type
     class procedure BinaryCompatiblePascalCoinECIESDecryptExistingPayloadDemo
       (const PrivateKeyInHex, EncryptedMessageInHex,
       ACurveName: string); static;
+
+    /// <summary>
+    /// Generate a PKCS#10 Certificate Signing Request using ECDSA
+    /// </summary>
+    class procedure GenerateCSRWithECDSA(); static;
+
+    /// <summary>
+    /// Generate a PKCS#10 Certificate Signing Request using Ed25519 (EdDSA)
+    /// </summary>
+    class procedure GenerateCSRWithEdDSA(); static;
   end;
 
 implementation
@@ -997,4 +1022,161 @@ begin
   FCurve := GetCurveByName(CurveName);
 end;
 
+class procedure TUsageExamples.GenerateCSRWithECDSA;
+
+  procedure GenerateCSRForCurve(const curveName, digestName: string);
+  var
+    curve: IX9ECParameters;
+    domain: IECDomainParameters;
+    generator: IECKeyPairGenerator;
+    keygenParams: IECKeyGenerationParameters;
+    KeyPair: IAsymmetricCipherKeyPair;
+    privParams: IECPrivateKeyParameters;
+    pubParams: IECPublicKeyParameters;
+    subject: IX500Name;
+    builder: IPkcs10CertificationRequestBuilder;
+    csr: IPkcs10CertificationRequest;
+    digest: IDigest;
+    pemString: string;
+    customExtOid: IDerObjectIdentifier;
+    customExtValue: IDerUtf8String;
+  begin
+    Writeln('=== Generating CSR with curve: ' + curveName + ' ===' + sLineBreak);
+
+    // 1. Generate EC Key Pair
+    curve := GetCurveByName(curveName);
+    domain := TECDomainParameters.Create(curve.Curve, curve.G, curve.N,
+      curve.H, curve.GetSeed);
+    generator := TECKeyPairGenerator.Create('ECDSA');
+    keygenParams := TECKeyGenerationParameters.Create(domain, FRandom);
+    generator.Init(keygenParams);
+
+    KeyPair := generator.GenerateKeyPair();
+    privParams := KeyPair.Private as IECPrivateKeyParameters;
+    pubParams := KeyPair.Public as IECPublicKeyParameters;
+
+    Writeln('Generated EC Key Pair using curve: ' + curveName);
+
+    // 2. Build X.500 Distinguished Name
+    subject := TX500NameBuilder.Create
+      .AddCommonName('Example CSR - ' + curveName)
+      .AddOrganization('CryptoLib4Pascal')
+      .AddOrganizationalUnit('Development')
+      .AddCountry('US')
+      .Build;
+
+    // 3. Create digest for signing
+    digest := TDigestUtilities.GetDigest(digestName);
+    Writeln('Using digest algorithm: ' + digest.AlgorithmName);
+
+    // 4. Create custom extension (example: application-specific OID)
+    customExtOid := TDerObjectIdentifier.Create('1.2.3.4.5.6.7.8.9');
+    customExtValue := TDerUtf8String.Create('CryptoLib4Pascal Custom Extension');
+
+    // 5. Build PKCS#10 CSR with extensions
+    builder := TECDSACertificationRequestBuilder.Create(digest);
+    csr := builder
+      .SetSubject(subject)
+      .SetPublicKey(pubParams)
+      .AddExtension(customExtOid, False, customExtValue)  // Custom extension
+      .AddSubjectKeyIdentifier()  // X.509 Subject Key Identifier
+      .Build(privParams);
+
+    Writeln('CSR built successfully with extensions!');
+
+    // 6. Get PEM encoded CSR
+    pemString := csr.GetPemEncoded;
+
+    Writeln('PEM Encoded CSR:');
+    Writeln(pemString);
+  end;
+
+const
+  MethodName = 'GenerateCSRWithECDSA';
+begin
+  Writeln('MethodName is: ' + MethodName + sLineBreak);
+  Writeln('Demonstrating PKCS#10 CSR generation with various ECDSA curves' + sLineBreak);
+
+  // Demonstrate with different curves
+  // P-256 (NIST prime256v1) - most commonly used for web certificates
+  GenerateCSRForCurve('P-256', 'SHA-256');
+
+  // P-384 (NIST secp384r1) - stronger security
+  GenerateCSRForCurve('P-384', 'SHA-384');
+
+  // P-521 (NIST secp521r1) - highest NIST security level
+  GenerateCSRForCurve('P-521', 'SHA-512');
+
+  // secp256k1 - used by Bitcoin and Ethereum
+  GenerateCSRForCurve('secp256k1', 'SHA-256');
+
+  Writeln('');
+end;
+
+class procedure TUsageExamples.GenerateCSRWithEdDSA;
+var
+  ed25519Instance: IEd25519;
+  generator: IEd25519KeyPairGenerator;
+  keygenParams: IEd25519KeyGenerationParameters;
+  KeyPair: IAsymmetricCipherKeyPair;
+  privParams: IEd25519PrivateKeyParameters;
+  pubParams: IEd25519PublicKeyParameters;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  pemString: string;
+  customExtOid: IDerObjectIdentifier;
+  customExtValue: IDerUtf8String;
+const
+  MethodName = 'GenerateCSRWithEdDSA';
+begin
+  Writeln('MethodName is: ' + MethodName + sLineBreak);
+  Writeln('Demonstrating PKCS#10 CSR generation with Ed25519 (EdDSA)' + sLineBreak);
+
+  // 1. Generate Ed25519 Key Pair
+  ed25519Instance := TEd25519.Create();
+  generator := TEd25519KeyPairGenerator.Create(ed25519Instance);
+  keygenParams := TEd25519KeyGenerationParameters.Create(FRandom);
+  generator.Init(keygenParams);
+
+  KeyPair := generator.GenerateKeyPair();
+  privParams := KeyPair.Private as IEd25519PrivateKeyParameters;
+  pubParams := KeyPair.Public as IEd25519PublicKeyParameters;
+
+  Writeln('Generated Ed25519 Key Pair');
+
+  // 2. Build X.500 Distinguished Name
+  subject := TX500NameBuilder.Create
+    .AddCommonName('Example Ed25519 CSR')
+    .AddOrganization('CryptoLib4Pascal')
+    .AddOrganizationalUnit('Development')
+    .AddCountry('US')
+    .Build;
+
+  Writeln('Built X.500 Distinguished Name');
+
+  // 3. Create custom extension (example: application-specific OID)
+  customExtOid := TDerObjectIdentifier.Create('1.2.3.4.5.6.7.8.9');
+  customExtValue := TDerUtf8String.Create('CryptoLib4Pascal Ed25519 Extension');
+
+  // 4. Build PKCS#10 CSR using Ed25519 with extensions
+  builder := TEdDSACertificationRequestBuilder.Create;
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(pubParams)
+    .AddExtension(customExtOid, False, customExtValue)  // Custom extension
+    .AddSubjectKeyIdentifier()  // X.509 Subject Key Identifier
+    .Build(privParams);
+
+  Writeln('CSR built successfully with Ed25519 and extensions!');
+
+  // 5. Get PEM encoded CSR
+  pemString := csr.GetPemEncoded;
+
+  Writeln('PEM Encoded CSR:');
+  Writeln(pemString);
+
+  Writeln('');
+end;
+
 end.

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

@@ -382,6 +382,14 @@ uses
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   ClpIShortenedDigest in '..\src\Utils\ClpIShortenedDigest.pas',
   ClpShortenedDigest in '..\src\Utils\ClpShortenedDigest.pas',
+  ClpAlgorithmIdentifier in '..\..\CryptoLib\src\Asn1\X509\ClpAlgorithmIdentifier.pas',
+  ClpIAlgorithmIdentifier in '..\..\CryptoLib\src\Interfaces\ClpIAlgorithmIdentifier.pas',
+  ClpSubjectPublicKeyInfo in '..\..\CryptoLib\src\Asn1\X509\ClpSubjectPublicKeyInfo.pas',
+  ClpISubjectPublicKeyInfo in '..\..\CryptoLib\src\Interfaces\ClpISubjectPublicKeyInfo.pas',
+  ClpX500Name in '..\..\CryptoLib\src\Asn1\X509\ClpX500Name.pas',
+  ClpIX500Name in '..\..\CryptoLib\src\Interfaces\ClpIX500Name.pas',
+  ClpPkcs10CertificationRequest in '..\..\CryptoLib\src\Asn1\Pkcs\ClpPkcs10CertificationRequest.pas',
+  ClpIPkcs10CertificationRequest in '..\..\CryptoLib\src\Interfaces\ClpIPkcs10CertificationRequest.pas',
   BlowfishTestVectors in '..\src\Crypto\BlowfishTestVectors.pas',
   BlockCipherVectorTests in '..\src\Crypto\BlockCipherVectorTests.pas',
   AESTestVectors in '..\src\Crypto\AESTestVectors.pas',
@@ -450,6 +458,7 @@ uses
   DHTests in '..\src\Crypto\DHTests.pas',
   Asn1IntegerTests in '..\src\Asn1\Asn1IntegerTests.pas',
   KMacTests in '..\src\Crypto\KMacTests.pas',
+  Pkcs10CertificationRequestTests in '..\src\Asn1\Pkcs10CertificationRequestTests.pas',
   CryptoLibTestBase in '..\src\CryptoLibTestBase.pas';
 
 begin

+ 1 - 0
CryptoLib.Tests/FreePascal.Tests/CryptoLib.lpr

@@ -74,6 +74,7 @@ uses
   DHTests,
   Asn1IntegerTests,
   KMacTests,
+  Pkcs10CertificationRequestTests,
   CryptoLibTestBase,
   ClpFixedSecureRandom,
   ClpIFixedSecureRandom,

+ 1 - 0
CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpr

@@ -72,6 +72,7 @@ uses
   DHTests,
   Asn1IntegerTests,
   KMacTests,
+  Pkcs10CertificationRequestTests,
   CryptoLibTestBase,
   ClpFixedSecureRandom,
   ClpIFixedSecureRandom,

+ 591 - 0
CryptoLib.Tests/src/Asn1/Pkcs10CertificationRequestTests.pas

@@ -0,0 +1,591 @@
+{ *********************************************************************************** }
+{ *                              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 Pkcs10CertificationRequestTests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+  SysUtils,
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  ClpBigInteger,
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpDigestUtilities,
+  ClpIDigest,
+  ClpAsn1Objects,
+  ClpIAsn1Objects,
+  ClpIX9ECParameters,
+  ClpIECDomainParameters,
+  ClpECDomainParameters,
+  ClpIECKeyPairGenerator,
+  ClpECKeyPairGenerator,
+  ClpIECKeyGenerationParameters,
+  ClpECKeyGenerationParameters,
+  ClpIAsymmetricCipherKeyPair,
+  ClpIECPrivateKeyParameters,
+  ClpIECPublicKeyParameters,
+  ClpCustomNamedCurves,
+  ClpX500Name,
+  ClpIX500Name,
+  ClpPkcs10CertificationRequest,
+  ClpIPkcs10CertificationRequest,
+  ClpECDsaSigner,
+  ClpIECDsaSigner,
+  ClpHMacDsaKCalculator,
+  ClpIHMacDsaKCalculator,
+  ClpSignersEncodings,
+  ClpISignersEncodings,
+  // Ed25519 support
+  ClpEd25519KeyPairGenerator,
+  ClpIEd25519KeyPairGenerator,
+  ClpEd25519KeyGenerationParameters,
+  ClpIEd25519KeyGenerationParameters,
+  ClpIEd25519PublicKeyParameters,
+  ClpIEd25519PrivateKeyParameters,
+  ClpEd25519,
+  ClpIEd25519,
+  ClpEd25519Signer,
+  ClpIEd25519Signer,
+  CryptoLibTestBase,
+  ClpCryptoLibTypes;
+
+  type
+  TTestPkcs10CertificationRequest = class(TCryptoLibAlgorithmTestCase)
+  private
+    FRandom: ISecureRandom;
+
+    function GenerateECKeyPairForCurve(const curveName: string): IAsymmetricCipherKeyPair;
+    function GenerateEd25519KeyPair: IAsymmetricCipherKeyPair;
+    procedure DoTestCSRForCurve(const curveName, digestName: string);
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+
+  published
+    // Test different hash algorithms with secp256k1
+    procedure TestBuildCSRWithSHA256;
+    procedure TestBuildCSRWithSHA384;
+    procedure TestBuildCSRWithSHA512;
+
+    // Test different curves with SHA-256
+    procedure TestCSRWithP256;
+    procedure TestCSRWithP384;
+    procedure TestCSRWithP521;
+    procedure TestCSRWithSecp256k1;
+
+    // Ed25519 tests
+    procedure TestCSRWithEd25519;
+    procedure TestEd25519SignatureVerification;
+
+    // Extension tests
+    procedure TestCSRWithSubjectKeyIdentifier;
+    procedure TestCSRWithCustomExtension;
+
+    // Other tests
+    procedure TestCSRSignatureVerification;
+    procedure TestX500NameBuilder;
+    procedure TestCSRDerEncoding;
+  end;
+
+implementation
+
+{ TTestPkcs10CertificationRequest }
+
+procedure TTestPkcs10CertificationRequest.SetUp;
+begin
+  inherited;
+  FRandom := TSecureRandom.Create();
+end;
+
+procedure TTestPkcs10CertificationRequest.TearDown;
+begin
+  inherited;
+end;
+
+function TTestPkcs10CertificationRequest.GenerateECKeyPairForCurve(
+  const curveName: string): IAsymmetricCipherKeyPair;
+var
+  curve: IX9ECParameters;
+  domain: IECDomainParameters;
+  generator: IECKeyPairGenerator;
+  keygenParams: IECKeyGenerationParameters;
+begin
+  curve := TCustomNamedCurves.GetByName(curveName);
+  CheckNotNull(curve, 'Curve ' + curveName + ' not found');
+
+  domain := TECDomainParameters.Create(curve.Curve, curve.G, curve.N,
+    curve.H, curve.GetSeed);
+  generator := TECKeyPairGenerator.Create('ECDSA');
+  keygenParams := TECKeyGenerationParameters.Create(domain, FRandom);
+  generator.Init(keygenParams);
+  Result := generator.GenerateKeyPair();
+end;
+
+function TTestPkcs10CertificationRequest.GenerateEd25519KeyPair: IAsymmetricCipherKeyPair;
+var
+  ed25519Instance: IEd25519;
+  generator: IEd25519KeyPairGenerator;
+  keygenParams: IEd25519KeyGenerationParameters;
+begin
+  ed25519Instance := TEd25519.Create();
+  generator := TEd25519KeyPairGenerator.Create(ed25519Instance);
+  keygenParams := TEd25519KeyGenerationParameters.Create(FRandom);
+  generator.Init(keygenParams);
+  Result := generator.GenerateKeyPair();
+end;
+
+procedure TTestPkcs10CertificationRequest.DoTestCSRForCurve(
+  const curveName, digestName: string);
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  digest: IDigest;
+  derBytes: TCryptoLibByteArray;
+  pubKey: IECPublicKeyParameters;
+  privKey: IECPrivateKeyParameters;
+begin
+  keyPair := GenerateECKeyPairForCurve(curveName);
+  pubKey := keyPair.Public as IECPublicKeyParameters;
+  privKey := keyPair.Private as IECPrivateKeyParameters;
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('Test ' + curveName)
+    .AddOrganization('CryptoLib4Pascal')
+    .AddCountry('US')
+    .Build;
+
+  digest := TDigestUtilities.GetDigest(digestName);
+
+  // digest passed to constructor
+  builder := TECDSACertificationRequestBuilder.Create(digest);
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(pubKey)
+    .AddSubjectKeyIdentifier()
+    .Build(privKey);
+
+  // Verify CSR was created
+  CheckNotNull(csr, 'CSR for ' + curveName + ' should not be nil');
+  CheckNotNull(csr.CertificationRequestInfo, 'CertificationRequestInfo should not be nil');
+  CheckNotNull(csr.SignatureAlgorithm, 'SignatureAlgorithm should not be nil');
+  CheckNotNull(csr.Signature, 'Signature should not be nil');
+
+  // Verify DER encoding works
+  derBytes := csr.GetEncoded;
+  CheckTrue(Length(derBytes) > 0, 'DER encoded CSR should not be empty');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestBuildCSRWithSHA256;
+begin
+  DoTestCSRForCurve('secp256k1', 'SHA-256');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestBuildCSRWithSHA384;
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  digest: IDigest;
+begin
+  keyPair := GenerateECKeyPairForCurve('secp256k1');
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('SHA384 Test')
+    .Build;
+
+  digest := TDigestUtilities.GetDigest('SHA-384');
+
+  builder := TECDSACertificationRequestBuilder.Create(digest);
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(keyPair.Public as IECPublicKeyParameters)
+    .Build(keyPair.Private as IECPrivateKeyParameters);
+
+  CheckNotNull(csr, 'CSR with SHA-384 should not be nil');
+
+  // Check algorithm OID contains SHA384
+  CheckTrue(csr.SignatureAlgorithm.Algorithm.Id = '1.2.840.10045.4.3.3',
+    'Signature algorithm should be ecdsa-with-SHA384');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestBuildCSRWithSHA512;
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  digest: IDigest;
+begin
+  keyPair := GenerateECKeyPairForCurve('secp256k1');
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('SHA512 Test')
+    .Build;
+
+  digest := TDigestUtilities.GetDigest('SHA-512');
+
+  builder := TECDSACertificationRequestBuilder.Create(digest);
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(keyPair.Public as IECPublicKeyParameters)
+    .Build(keyPair.Private as IECPrivateKeyParameters);
+
+  CheckNotNull(csr, 'CSR with SHA-512 should not be nil');
+
+  // Check algorithm OID contains SHA512
+  CheckTrue(csr.SignatureAlgorithm.Algorithm.Id = '1.2.840.10045.4.3.4',
+    'Signature algorithm should be ecdsa-with-SHA512');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRWithP256;
+begin
+  DoTestCSRForCurve('P-256', 'SHA-256');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRWithP384;
+begin
+  DoTestCSRForCurve('P-384', 'SHA-384');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRWithP521;
+begin
+  DoTestCSRForCurve('P-521', 'SHA-512');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRWithSecp256k1;
+begin
+  DoTestCSRForCurve('secp256k1', 'SHA-256');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRSignatureVerification;
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  digest: IDigest;
+  tbsBytes, hashBytes, sigBytes: TCryptoLibByteArray;
+  signer: IECDsaSigner;
+  sigValues: TCryptoLibGenericArray<TBigInteger>;
+  privKey: IECPrivateKeyParameters;
+  pubKey: IECPublicKeyParameters;
+  verifyResult: Boolean;
+begin
+  keyPair := GenerateECKeyPairForCurve('secp256k1');
+  privKey := keyPair.Private as IECPrivateKeyParameters;
+  pubKey := keyPair.Public as IECPublicKeyParameters;
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('Verify Test')
+    .AddOrganization('CryptoLib4Pascal')
+    .Build;
+
+  digest := TDigestUtilities.GetDigest('SHA-256');
+
+  builder := TECDSACertificationRequestBuilder.Create(digest);
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(pubKey)
+    .Build(privKey);
+
+  // Get the TBS (to-be-signed) data
+  tbsBytes := csr.CertificationRequestInfo.ToAsn1Object.GetEncoded(TAsn1Encodable.Der);
+
+  // Hash it with SHA-256
+  digest.Reset;
+  System.SetLength(hashBytes, digest.GetDigestSize);
+  digest.BlockUpdate(tbsBytes, 0, Length(tbsBytes));
+  digest.DoFinal(hashBytes, 0);
+
+  // Get signature bytes and decode
+  sigBytes := csr.Signature.GetOctets;
+  sigValues := TStandardDsaEncoding.Instance.Decode(privKey.Parameters.N, sigBytes);
+
+  // Verify signature
+  signer := TECDsaSigner.Create();
+  signer.Init(False, pubKey);
+  verifyResult := signer.VerifySignature(hashBytes, sigValues[0], sigValues[1]);
+
+  CheckTrue(verifyResult, 'CSR signature verification should pass');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestX500NameBuilder;
+var
+  subject: IX500Name;
+  derBytes: TCryptoLibByteArray;
+begin
+  subject := TX500NameBuilder.Create
+    .AddCommonName('Test Common Name')
+    .AddOrganization('Test Organization')
+    .AddOrganizationalUnit('Test OU')
+    .AddCountry('US')
+    .AddState('California')
+    .AddLocality('San Francisco')
+    .AddEmailAddress('[email protected]')
+    .Build;
+
+  CheckNotNull(subject, 'X500Name should not be nil');
+
+  // Verify it can be DER encoded
+  derBytes := subject.ToAsn1Object.GetEncoded(TAsn1Encodable.Der);
+  CheckTrue(Length(derBytes) > 0, 'X500Name DER encoding should not be empty');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRDerEncoding;
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  digest: IDigest;
+  derBytes: TCryptoLibByteArray;
+  pemString: string;
+  seq: IAsn1Sequence;
+begin
+  keyPair := GenerateECKeyPairForCurve('secp256k1');
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('DER Test')
+    .Build;
+
+  digest := TDigestUtilities.GetDigest('SHA-256');
+
+  builder := TECDSACertificationRequestBuilder.Create(digest);
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(keyPair.Public as IECPublicKeyParameters)
+    .Build(keyPair.Private as IECPrivateKeyParameters);
+
+  // Test DER encoding
+  derBytes := csr.GetEncoded;
+  CheckTrue(Length(derBytes) > 0, 'DER bytes should not be empty');
+
+  // Verify it can be parsed back as ASN1 sequence
+  seq := TAsn1Sequence.GetInstance(derBytes);
+  CheckNotNull(seq, 'Should be able to parse CSR as ASN1 sequence');
+  CheckEquals(3, seq.Count, 'CSR should have 3 elements');
+
+  // Test PEM encoding
+  pemString := csr.GetPemEncoded;
+  CheckTrue(Length(pemString) > 0, 'PEM string should not be empty');
+  CheckTrue(Pos('-----BEGIN CERTIFICATE REQUEST-----', pemString) > 0,
+    'PEM should contain BEGIN header');
+  CheckTrue(Pos('-----END CERTIFICATE REQUEST-----', pemString) > 0,
+    'PEM should contain END footer');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRWithEd25519;
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  derBytes: TCryptoLibByteArray;
+  pemString: string;
+begin
+  keyPair := GenerateEd25519KeyPair;
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('Ed25519 Test')
+    .AddOrganization('CryptoLib4Pascal')
+    .AddCountry('US')
+    .Build;
+
+  // TEdDSACertificationRequestBuilder, no digest needed
+  builder := TEdDSACertificationRequestBuilder.Create;
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(keyPair.Public as IEd25519PublicKeyParameters)
+    .AddSubjectKeyIdentifier()
+    .Build(keyPair.Private as IEd25519PrivateKeyParameters);
+
+  // Verify CSR was created
+  CheckNotNull(csr, 'CSR with Ed25519 should not be nil');
+  CheckNotNull(csr.CertificationRequestInfo, 'CertificationRequestInfo should not be nil');
+  CheckNotNull(csr.SignatureAlgorithm, 'SignatureAlgorithm should not be nil');
+  CheckNotNull(csr.Signature, 'Signature should not be nil');
+
+  // Check signature algorithm OID is Ed25519 (1.3.101.112)
+  CheckTrue(csr.SignatureAlgorithm.Algorithm.Id = '1.3.101.112',
+    'Signature algorithm should be Ed25519');
+
+  // Verify DER encoding works
+  derBytes := csr.GetEncoded;
+  CheckTrue(Length(derBytes) > 0, 'DER encoded CSR should not be empty');
+
+  // Verify PEM encoding works
+  pemString := csr.GetPemEncoded;
+  CheckTrue(Length(pemString) > 0, 'PEM string should not be empty');
+  CheckTrue(Pos('-----BEGIN CERTIFICATE REQUEST-----', pemString) > 0,
+    'PEM should contain BEGIN header');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestEd25519SignatureVerification;
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  tbsBytes, sigBytes: TCryptoLibByteArray;
+  signer: IEd25519Signer;
+  ed25519Instance: IEd25519;
+  privKey: IEd25519PrivateKeyParameters;
+  pubKey: IEd25519PublicKeyParameters;
+  verifyResult: Boolean;
+begin
+  keyPair := GenerateEd25519KeyPair;
+  privKey := keyPair.Private as IEd25519PrivateKeyParameters;
+  pubKey := keyPair.Public as IEd25519PublicKeyParameters;
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('Ed25519 Verify Test')
+    .AddOrganization('CryptoLib4Pascal')
+    .Build;
+
+  builder := TEdDSACertificationRequestBuilder.Create;
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(pubKey)
+    .Build(privKey);
+
+  // Get the TBS (to-be-signed) data
+  tbsBytes := csr.CertificationRequestInfo.ToAsn1Object.GetEncoded(TAsn1Encodable.Der);
+
+  // Get signature bytes
+  sigBytes := csr.Signature.GetOctets;
+
+  // Verify signature using Ed25519Signer
+  ed25519Instance := TEd25519.Create();
+  signer := TEd25519Signer.Create(ed25519Instance);
+  signer.Init(False, pubKey);
+  signer.BlockUpdate(tbsBytes, 0, Length(tbsBytes));
+  verifyResult := signer.VerifySignature(sigBytes);
+
+  CheckTrue(verifyResult, 'Ed25519 CSR signature verification should pass');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRWithSubjectKeyIdentifier;
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  digest: IDigest;
+  derBytes: TCryptoLibByteArray;
+  pemString: string;
+begin
+  keyPair := GenerateECKeyPairForCurve('secp256k1');
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('Extension Test')
+    .AddOrganization('CryptoLib4Pascal')
+    .AddCountry('US')
+    .Build;
+
+  digest := TDigestUtilities.GetDigest('SHA-256');
+
+  // Build CSR with Subject Key Identifier extension
+  builder := TECDSACertificationRequestBuilder.Create(digest);
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(keyPair.Public as IECPublicKeyParameters)
+    .AddSubjectKeyIdentifier()  // Add Subject Key Identifier extension
+    .Build(keyPair.Private as IECPrivateKeyParameters);
+
+  // Verify CSR was created
+  CheckNotNull(csr, 'CSR with SKI should not be nil');
+  CheckNotNull(csr.CertificationRequestInfo, 'CertificationRequestInfo should not be nil');
+
+  // Verify DER encoding works
+  derBytes := csr.GetEncoded;
+  CheckTrue(Length(derBytes) > 0, 'DER encoded CSR should not be empty');
+
+  // Verify PEM encoding works
+  pemString := csr.GetPemEncoded;
+  CheckTrue(Length(pemString) > 0, 'PEM string should not be empty');
+  CheckTrue(Pos('-----BEGIN CERTIFICATE REQUEST-----', pemString) > 0,
+    'PEM should contain BEGIN header');
+end;
+
+procedure TTestPkcs10CertificationRequest.TestCSRWithCustomExtension;
+var
+  keyPair: IAsymmetricCipherKeyPair;
+  subject: IX500Name;
+  builder: IPkcs10CertificationRequestBuilder;
+  csr: IPkcs10CertificationRequest;
+  digest: IDigest;
+  derBytes: TCryptoLibByteArray;
+  customOid: IDerObjectIdentifier;
+  customValue: IDerUtf8String;
+begin
+  keyPair := GenerateECKeyPairForCurve('secp256k1');
+
+  subject := TX500NameBuilder.Create
+    .AddCommonName('Custom Extension Test')
+    .AddOrganization('CryptoLib4Pascal')
+    .Build;
+
+  digest := TDigestUtilities.GetDigest('SHA-256');
+
+  // Create custom extension OID and value
+  // Using a test OID: 1.2.3.4.5.6.7.8.9
+  customOid := TDerObjectIdentifier.Create('1.2.3.4.5.6.7.8.9');
+  customValue := TDerUtf8String.Create('Test Extension Value');
+
+  // Build CSR with custom extension
+  builder := TECDSACertificationRequestBuilder.Create(digest);
+  csr := builder
+    .SetSubject(subject)
+    .SetPublicKey(keyPair.Public as IECPublicKeyParameters)
+    .AddExtension(customOid, False, customValue)  // Non-critical custom extension
+    .AddSubjectKeyIdentifier()  // Also add SKI
+    .Build(keyPair.Private as IECPrivateKeyParameters);
+
+  // Verify CSR was created
+  CheckNotNull(csr, 'CSR with custom extension should not be nil');
+  CheckNotNull(csr.CertificationRequestInfo, 'CertificationRequestInfo should not be nil');
+
+  // Verify DER encoding works
+  derBytes := csr.GetEncoded;
+  CheckTrue(Length(derBytes) > 0, 'DER encoded CSR should not be empty');
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestPkcs10CertificationRequest);
+{$ELSE}
+  RegisterTest(TTestPkcs10CertificationRequest.Suite);
+{$ENDIF FPC}
+
+end.

+ 719 - 0
CryptoLib/src/Asn1/Pkcs/ClpPkcs10CertificationRequest.pas

@@ -0,0 +1,719 @@
+{ *********************************************************************************** }
+{ *                              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 ClpPkcs10CertificationRequest;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpAsn1Objects,
+  ClpIAsn1Objects,
+  ClpAlgorithmIdentifier,
+  ClpIAlgorithmIdentifier,
+  ClpSubjectPublicKeyInfo,
+  ClpISubjectPublicKeyInfo,
+  ClpIX500Name,
+  ClpIPkcs10CertificationRequest,
+  ClpIAsymmetricKeyParameter,
+  ClpIECPublicKeyParameters,
+  ClpIECPrivateKeyParameters,
+  ClpIDigest,
+  ClpDigestUtilities,
+  ClpECDsaSigner,
+  ClpIECDsaSigner,
+  ClpSignersEncodings,
+  ClpISignersEncodings,
+  ClpHMacDsaKCalculator,
+  ClpIHMacDsaKCalculator,
+  ClpX9ObjectIdentifiers,
+  ClpEncoders,
+  ClpBigInteger,
+  // EdDSA support
+  ClpIEd25519PublicKeyParameters,
+  ClpIEd25519PrivateKeyParameters,
+  ClpSignerUtilities,
+  ClpISigner,
+  ClpEdECObjectIdentifiers,
+  ClpCryptoLibTypes,
+  Generics.Collections;
+
+resourcestring
+  SInvalidPkcs10Request = 'Invalid PKCS#10 Certification Request: %s';
+  SBadSequenceSize = 'Bad Sequence Size: %d';
+  SUnsupportedDigest = 'Unsupported digest algorithm: %s';
+  SPublicKeyNotSet = 'Public key must be set before adding Subject Key Identifier';
+
+type
+  /// <summary>
+  /// PKCS#9 Object Identifiers
+  /// </summary>
+  TPkcs9Oids = class abstract(TObject)
+  strict private
+    class var
+      FExtensionRequest: IDerObjectIdentifier;
+      class function GetExtensionRequest: IDerObjectIdentifier; static;
+  public
+    /// <summary>extensionRequest (1.2.840.113549.1.9.14)</summary>
+    class property ExtensionRequest: IDerObjectIdentifier read GetExtensionRequest;
+  end;
+
+  /// <summary>
+  /// X.509 Extension Object Identifiers
+  /// </summary>
+  TX509ExtensionOids = class abstract(TObject)
+  strict private
+    class var
+      FSubjectKeyIdentifier: IDerObjectIdentifier;
+      class function GetSubjectKeyIdentifier: IDerObjectIdentifier; static;
+  public
+    /// <summary>subjectKeyIdentifier (2.5.29.14)</summary>
+    class property SubjectKeyIdentifier: IDerObjectIdentifier read GetSubjectKeyIdentifier;
+  end;
+
+type
+  /// <summary>
+  /// PKCS#10 CertificationRequestInfo - the to-be-signed portion
+  /// CertificationRequestInfo ::= SEQUENCE {
+  ///   version INTEGER { v1(0) },
+  ///   subject Name,
+  ///   subjectPKInfo SubjectPublicKeyInfo,
+  ///   attributes [0] IMPLICIT Attributes {{ CRIAttributes }} }
+  /// </summary>
+  TPkcs10CertificationRequestInfo = class(TAsn1Encodable, IPkcs10CertificationRequestInfo)
+
+  strict private
+  var
+    FVersion: IDerInteger;
+    FSubject: IX500Name;
+    FSubjectPublicKeyInfo: ISubjectPublicKeyInfo;
+    FAttributes: IDerTaggedObject;
+
+    function GetVersion: IDerInteger;
+    function GetSubject: IX500Name;
+    function GetSubjectPublicKeyInfo: ISubjectPublicKeyInfo;
+
+  public
+    constructor Create(const subject: IX500Name;
+      const subjectPublicKeyInfo: ISubjectPublicKeyInfo;
+      const attributes: IDerTaggedObject = nil); overload;
+
+    function ToAsn1Object(): IAsn1Object; override;
+
+    property Version: IDerInteger read GetVersion;
+    property Subject: IX500Name read GetSubject;
+    property SubjectPublicKeyInfo: ISubjectPublicKeyInfo read GetSubjectPublicKeyInfo;
+  end;
+
+type
+  /// <summary>
+  /// Complete PKCS#10 CertificationRequest
+  /// CertificationRequest ::= SEQUENCE {
+  ///   certificationRequestInfo CertificationRequestInfo,
+  ///   signatureAlgorithm AlgorithmIdentifier,
+  ///   signature BIT STRING }
+  /// </summary>
+  TPkcs10CertificationRequest = class(TAsn1Encodable, IPkcs10CertificationRequest)
+
+  strict private
+  var
+    FCertificationRequestInfo: IPkcs10CertificationRequestInfo;
+    FSignatureAlgorithm: IAlgorithmIdentifier;
+    FSignature: IDerBitString;
+
+    function GetCertificationRequestInfo: IPkcs10CertificationRequestInfo;
+    function GetSignatureAlgorithm: IAlgorithmIdentifier;
+    function GetSignature: IDerBitString;
+
+  public
+    constructor Create(const certReqInfo: IPkcs10CertificationRequestInfo;
+      const sigAlg: IAlgorithmIdentifier; const signature: IDerBitString);
+
+    function ToAsn1Object(): IAsn1Object; override;
+    function GetEncoded(): TCryptoLibByteArray; overload;
+    function GetPemEncoded: string;
+
+    property CertificationRequestInfo: IPkcs10CertificationRequestInfo read GetCertificationRequestInfo;
+    property SignatureAlgorithm: IAlgorithmIdentifier read GetSignatureAlgorithm;
+    property Signature: IDerBitString read GetSignature;
+  end;
+
+type
+  /// <summary>
+  /// Abstract base class for PKCS#10 Certification Request Builders.
+  /// Provides common functionality for SetSubject and CSR creation.
+  /// </summary>
+  TPkcs10CertificationRequestBuilderBase = class abstract(TInterfacedObject, IPkcs10CertificationRequestBuilder)
+  strict protected
+  var
+    FSubject: IX500Name;
+    FExtensions: TList<IAsn1Encodable>;
+    FPublicKeyBytes: TCryptoLibByteArray;
+
+    /// <summary>
+    /// Creates the final CSR from the provided components.
+    /// Shared helper used by all subclasses.
+    /// </summary>
+    function CreateCSR(const subjectPKInfo: ISubjectPublicKeyInfo;
+      const sigAlg: IAlgorithmIdentifier;
+      const sigBytes: TCryptoLibByteArray): IPkcs10CertificationRequest;
+
+    /// <summary>
+    /// Builds the extensionRequest attribute from stored extensions.
+    /// </summary>
+    function BuildAttributes: IDerTaggedObject;
+
+    /// <summary>
+    /// Stores the public key bytes for Subject Key Identifier computation.
+    /// </summary>
+    procedure SetPublicKeyBytes(const pubKeyBytes: TCryptoLibByteArray);
+
+  public
+    constructor Create();
+    destructor Destroy; override;
+
+    function SetSubject(const subject: IX500Name): IPkcs10CertificationRequestBuilder;
+    function SetPublicKey(const publicKey: IAsymmetricKeyParameter): IPkcs10CertificationRequestBuilder; virtual; abstract;
+    function Build(const privateKey: IAsymmetricKeyParameter): IPkcs10CertificationRequest; virtual; abstract;
+    function AddExtension(const oid: IDerObjectIdentifier; critical: Boolean;
+      const value: IAsn1Encodable): IPkcs10CertificationRequestBuilder;
+    function AddSubjectKeyIdentifier: IPkcs10CertificationRequestBuilder;
+  end;
+
+type
+  /// <summary>
+  /// ECDSA-based PKCS#10 Certification Request Builder.
+  /// Digest algorithm is specified at construction time.
+  /// </summary>
+  TECDSACertificationRequestBuilder = class(TPkcs10CertificationRequestBuilderBase)
+  strict private
+  class var
+    FDigestToOidMap: TDictionary<string, IDerObjectIdentifier>;
+
+  var
+    FPublicKey: IECPublicKeyParameters;
+    FDigest: IDigest;
+
+    function GetSignatureAlgorithmOid: IDerObjectIdentifier;
+
+    class constructor Create;
+    class destructor Destroy;
+
+  public
+    /// <summary>
+    /// Create ECDSA builder with specified digest algorithm.
+    /// </summary>
+    constructor Create(const digest: IDigest);
+
+    function SetPublicKey(const publicKey: IAsymmetricKeyParameter): IPkcs10CertificationRequestBuilder; override;
+    function Build(const privateKey: IAsymmetricKeyParameter): IPkcs10CertificationRequest; override;
+  end;
+
+type
+  /// <summary>
+  /// EdDSA-based PKCS#10 Certification Request Builder.
+  /// Supports EdDSA (Ed25519). No digest parameter needed.
+  /// </summary>
+  TEdDSACertificationRequestBuilder = class(TPkcs10CertificationRequestBuilderBase)
+  strict private
+  var
+    FEd25519PublicKey: IEd25519PublicKeyParameters;
+
+  public
+    constructor Create();
+
+    function SetPublicKey(const publicKey: IAsymmetricKeyParameter): IPkcs10CertificationRequestBuilder; override;
+    function Build(const privateKey: IAsymmetricKeyParameter): IPkcs10CertificationRequest; override;
+  end;
+
+implementation
+
+{ TPkcs10CertificationRequestInfo }
+
+constructor TPkcs10CertificationRequestInfo.Create(const subject: IX500Name;
+  const subjectPublicKeyInfo: ISubjectPublicKeyInfo;
+  const attributes: IDerTaggedObject = nil);
+begin
+  inherited Create();
+  FVersion := TDerInteger.Create(0); // v1(0)
+  FSubject := subject;
+  FSubjectPublicKeyInfo := subjectPublicKeyInfo;
+  FAttributes := attributes;
+end;
+
+function TPkcs10CertificationRequestInfo.GetVersion: IDerInteger;
+begin
+  Result := FVersion;
+end;
+
+function TPkcs10CertificationRequestInfo.GetSubject: IX500Name;
+begin
+  Result := FSubject;
+end;
+
+function TPkcs10CertificationRequestInfo.GetSubjectPublicKeyInfo: ISubjectPublicKeyInfo;
+begin
+  Result := FSubjectPublicKeyInfo;
+end;
+
+function TPkcs10CertificationRequestInfo.ToAsn1Object: IAsn1Object;
+var
+  v: IAsn1EncodableVector;
+  subjectAsn1, pkInfoAsn1: IAsn1Object;
+  attrsToUse: IDerTaggedObject;
+begin
+  // Get the underlying ASN1 objects
+  subjectAsn1 := FSubject.ToAsn1Object;
+  pkInfoAsn1 := FSubjectPublicKeyInfo.ToAsn1Object;
+
+  // Use provided attributes or empty SET
+  if FAttributes <> nil then
+    attrsToUse := FAttributes
+  else
+    attrsToUse := TDerTaggedObject.Create(False, 0,
+      TDerSequence.Create() as IAsn1Encodable);
+
+  // Build using vector
+  v := TAsn1EncodableVector.Create();
+  v.Add(FVersion);
+  v.Add(subjectAsn1);
+  v.Add(pkInfoAsn1);
+  v.Add(attrsToUse);
+
+  Result := TDerSequence.FromVector(v);
+end;
+
+{ TPkcs10CertificationRequest }
+
+constructor TPkcs10CertificationRequest.Create(
+  const certReqInfo: IPkcs10CertificationRequestInfo;
+  const sigAlg: IAlgorithmIdentifier; const signature: IDerBitString);
+begin
+  inherited Create();
+  FCertificationRequestInfo := certReqInfo;
+  FSignatureAlgorithm := sigAlg;
+  FSignature := signature;
+end;
+
+function TPkcs10CertificationRequest.GetCertificationRequestInfo: IPkcs10CertificationRequestInfo;
+begin
+  Result := FCertificationRequestInfo;
+end;
+
+function TPkcs10CertificationRequest.GetSignatureAlgorithm: IAlgorithmIdentifier;
+begin
+  Result := FSignatureAlgorithm;
+end;
+
+function TPkcs10CertificationRequest.GetSignature: IDerBitString;
+begin
+  Result := FSignature;
+end;
+
+function TPkcs10CertificationRequest.ToAsn1Object: IAsn1Object;
+var
+  v: IAsn1EncodableVector;
+  certReqInfoAsn1, sigAlgAsn1: IAsn1Object;
+begin
+  certReqInfoAsn1 := FCertificationRequestInfo.ToAsn1Object;
+  sigAlgAsn1 := FSignatureAlgorithm.ToAsn1Object;
+
+  v := TAsn1EncodableVector.Create();
+  v.Add(certReqInfoAsn1);
+  v.Add(sigAlgAsn1);
+  v.Add(FSignature);
+
+  Result := TDerSequence.FromVector(v);
+end;
+
+function TPkcs10CertificationRequest.GetEncoded: TCryptoLibByteArray;
+begin
+  Result := ToAsn1Object.GetEncoded(TAsn1Encodable.Der);
+end;
+
+function TPkcs10CertificationRequest.GetPemEncoded: string;
+var
+  derBytes: TCryptoLibByteArray;
+  base64: string;
+  sb: TStringBuilder;
+  i, lineLen: Integer;
+begin
+  derBytes := GetEncoded;
+  base64 := TBase64.Encode(derBytes);
+
+  sb := TStringBuilder.Create;
+  try
+    sb.AppendLine('-----BEGIN CERTIFICATE REQUEST-----');
+
+    // Split into 64-character lines
+    i := 1;
+    lineLen := 64;
+    while i <= Length(base64) do
+    begin
+      if i + lineLen - 1 <= Length(base64) then
+        sb.AppendLine(Copy(base64, i, lineLen))
+      else
+        sb.AppendLine(Copy(base64, i, Length(base64) - i + 1));
+      Inc(i, lineLen);
+    end;
+
+    sb.Append('-----END CERTIFICATE REQUEST-----');
+    Result := sb.ToString;
+  finally
+    sb.Free;
+  end;
+end;
+
+{ TPkcs9Oids }
+
+class function TPkcs9Oids.GetExtensionRequest: IDerObjectIdentifier;
+begin
+  if FExtensionRequest = nil then
+    FExtensionRequest := TDerObjectIdentifier.Create('1.2.840.113549.1.9.14');
+  Result := FExtensionRequest;
+end;
+
+{ TX509ExtensionOids }
+
+class function TX509ExtensionOids.GetSubjectKeyIdentifier: IDerObjectIdentifier;
+begin
+  if FSubjectKeyIdentifier = nil then
+    FSubjectKeyIdentifier := TDerObjectIdentifier.Create('2.5.29.14');
+  Result := FSubjectKeyIdentifier;
+end;
+
+{ TPkcs10CertificationRequestBuilderBase }
+
+constructor TPkcs10CertificationRequestBuilderBase.Create;
+begin
+  inherited Create();
+  FSubject := nil;
+  FExtensions := TList<IAsn1Encodable>.Create;
+  FPublicKeyBytes := nil;
+end;
+
+destructor TPkcs10CertificationRequestBuilderBase.Destroy;
+begin
+  FExtensions.Free;
+  inherited Destroy;
+end;
+
+function TPkcs10CertificationRequestBuilderBase.SetSubject(
+  const subject: IX500Name): IPkcs10CertificationRequestBuilder;
+begin
+  FSubject := subject;
+  Result := Self;
+end;
+
+procedure TPkcs10CertificationRequestBuilderBase.SetPublicKeyBytes(
+  const pubKeyBytes: TCryptoLibByteArray);
+begin
+  FPublicKeyBytes := pubKeyBytes;
+end;
+
+function TPkcs10CertificationRequestBuilderBase.AddExtension(
+  const oid: IDerObjectIdentifier; critical: Boolean;
+  const value: IAsn1Encodable): IPkcs10CertificationRequestBuilder;
+var
+  extSeqV: IAsn1EncodableVector;
+  extValueBytes: TCryptoLibByteArray;
+  extValueOctet: IDerOctetString;
+begin
+  // Extension ::= SEQUENCE { extnID, critical, extnValue OCTET STRING }
+  extSeqV := TAsn1EncodableVector.Create();
+  extSeqV.Add(oid);
+  if critical then
+    extSeqV.Add(TDerBoolean.True);
+
+  // Encode value as OCTET STRING containing DER encoding
+  extValueBytes := value.ToAsn1Object.GetEncoded(TAsn1Encodable.Der);
+  extValueOctet := TDerOctetString.Create(extValueBytes);
+  extSeqV.Add(extValueOctet);
+
+  FExtensions.Add(TDerSequence.FromVector(extSeqV));
+  Result := Self;
+end;
+
+function TPkcs10CertificationRequestBuilderBase.AddSubjectKeyIdentifier:
+  IPkcs10CertificationRequestBuilder;
+var
+  sha1Digest: IDigest;
+  hashBytes: TCryptoLibByteArray;
+  skiValue: IDerOctetString;
+begin
+  if Length(FPublicKeyBytes) = 0 then
+    raise EInvalidOperationCryptoLibException.Create(SPublicKeyNotSet);
+
+  // Compute SHA-1 hash of public key bytes
+  sha1Digest := TDigestUtilities.GetDigest('SHA-1');
+  System.SetLength(hashBytes, sha1Digest.GetDigestSize);
+  sha1Digest.BlockUpdate(FPublicKeyBytes, 0, Length(FPublicKeyBytes));
+  sha1Digest.DoFinal(hashBytes, 0);
+
+  // Subject Key Identifier is an OCTET STRING
+  skiValue := TDerOctetString.Create(hashBytes);
+
+  // Add as extension (not critical)
+  Result := AddExtension(TX509ExtensionOids.SubjectKeyIdentifier, False, skiValue);
+end;
+
+function TPkcs10CertificationRequestBuilderBase.BuildAttributes: IDerTaggedObject;
+var
+  extensionsSeq: IDerSequence;
+  extV: IAsn1EncodableVector;
+  extReqSetV: IAsn1EncodableVector;
+  attrSeqV: IAsn1EncodableVector;
+  attrSeq: IDerSequence;
+  attrsSetV: IAsn1EncodableVector;
+  ext: IAsn1Encodable;
+begin
+  if FExtensions.Count = 0 then
+  begin
+    // No extensions - return empty attributes
+    Result := TDerTaggedObject.Create(False, 0,
+      TDerSequence.Create() as IAsn1Encodable);
+    Exit;
+  end;
+
+  // Build Extensions SEQUENCE
+  extV := TAsn1EncodableVector.Create();
+  for ext in FExtensions do
+    extV.Add(ext);
+  extensionsSeq := TDerSequence.FromVector(extV);
+
+  // extensionRequest attribute value is SET { Extensions }
+  extReqSetV := TAsn1EncodableVector.Create();
+  extReqSetV.Add(extensionsSeq);
+
+  // Attribute ::= SEQUENCE { type OID, values SET }
+  attrSeqV := TAsn1EncodableVector.Create();
+  attrSeqV.Add(TPkcs9Oids.ExtensionRequest);
+  attrSeqV.Add(TDerSet.FromVector(extReqSetV, False));
+  attrSeq := TDerSequence.FromVector(attrSeqV);
+
+  // Attributes is SET OF Attribute (but using SEQUENCE for [0] IMPLICIT)
+  attrsSetV := TAsn1EncodableVector.Create();
+  attrsSetV.Add(attrSeq);
+
+  Result := TDerTaggedObject.Create(False, 0,
+    TDerSequence.FromVector(attrsSetV) as IAsn1Encodable);
+end;
+
+function TPkcs10CertificationRequestBuilderBase.CreateCSR(
+  const subjectPKInfo: ISubjectPublicKeyInfo;
+  const sigAlg: IAlgorithmIdentifier;
+  const sigBytes: TCryptoLibByteArray): IPkcs10CertificationRequest;
+var
+  certReqInfo: IPkcs10CertificationRequestInfo;
+  sigBitString: IDerBitString;
+  attrs: IDerTaggedObject;
+begin
+  // Build attributes with extensions
+  attrs := BuildAttributes;
+
+  // Build CertificationRequestInfo with attributes
+  certReqInfo := TPkcs10CertificationRequestInfo.Create(FSubject, subjectPKInfo, attrs);
+
+  sigBitString := TDerBitString.Create(sigBytes);
+
+  Result := TPkcs10CertificationRequest.Create(certReqInfo, sigAlg, sigBitString);
+end;
+
+{ TECDSACertificationRequestBuilder }
+
+constructor TECDSACertificationRequestBuilder.Create(const digest: IDigest);
+begin
+  inherited Create();
+  FPublicKey := nil;
+  FDigest := digest;
+end;
+
+function TECDSACertificationRequestBuilder.SetPublicKey(
+  const publicKey: IAsymmetricKeyParameter): IPkcs10CertificationRequestBuilder;
+begin
+  if not Supports(publicKey, IECPublicKeyParameters) then
+    raise EArgumentCryptoLibException.Create('Expected IECPublicKeyParameters');
+  FPublicKey := publicKey as IECPublicKeyParameters;
+  // Store encoded point for SKI computation
+  SetPublicKeyBytes(FPublicKey.Q.GetEncoded(False));
+  Result := Self;
+end;
+
+class constructor TECDSACertificationRequestBuilder.Create;
+begin
+  FDigestToOidMap := TDictionary<string, IDerObjectIdentifier>.Create;
+
+  // SHA-256 variants
+  FDigestToOidMap.Add('SHA-256', TX9ObjectIdentifiers.ECDsaWithSha256);
+  FDigestToOidMap.Add('SHA256', TX9ObjectIdentifiers.ECDsaWithSha256);
+  FDigestToOidMap.Add('SHA2_256', TX9ObjectIdentifiers.ECDsaWithSha256);
+
+  // SHA-384 variants
+  FDigestToOidMap.Add('SHA-384', TX9ObjectIdentifiers.ECDsaWithSha384);
+  FDigestToOidMap.Add('SHA384', TX9ObjectIdentifiers.ECDsaWithSha384);
+  FDigestToOidMap.Add('SHA2_384', TX9ObjectIdentifiers.ECDsaWithSha384);
+
+  // SHA-512 variants
+  FDigestToOidMap.Add('SHA-512', TX9ObjectIdentifiers.ECDsaWithSha512);
+  FDigestToOidMap.Add('SHA512', TX9ObjectIdentifiers.ECDsaWithSha512);
+  FDigestToOidMap.Add('SHA2_512', TX9ObjectIdentifiers.ECDsaWithSha512);
+
+  // SHA-224 variants
+  FDigestToOidMap.Add('SHA-224', TX9ObjectIdentifiers.ECDsaWithSha224);
+  FDigestToOidMap.Add('SHA224', TX9ObjectIdentifiers.ECDsaWithSha224);
+  FDigestToOidMap.Add('SHA2_224', TX9ObjectIdentifiers.ECDsaWithSha224);
+
+  // SHA-1 variants
+  FDigestToOidMap.Add('SHA-1', TX9ObjectIdentifiers.ECDsaWithSha1);
+  FDigestToOidMap.Add('SHA1', TX9ObjectIdentifiers.ECDsaWithSha1);
+end;
+
+class destructor TECDSACertificationRequestBuilder.Destroy;
+begin
+  FDigestToOidMap.Free;
+end;
+
+function TECDSACertificationRequestBuilder.GetSignatureAlgorithmOid: IDerObjectIdentifier;
+var
+  digestName: string;
+begin
+  digestName := UpperCase(FDigest.AlgorithmName);
+
+  if not FDigestToOidMap.TryGetValue(digestName, Result) then
+    raise EArgumentCryptoLibException.CreateResFmt(@SUnsupportedDigest,
+      [FDigest.AlgorithmName]);
+end;
+
+function TECDSACertificationRequestBuilder.Build(
+  const privateKey: IAsymmetricKeyParameter): IPkcs10CertificationRequest;
+var
+  ecPrivKey: IECPrivateKeyParameters;
+  subjectPKInfo: ISubjectPublicKeyInfo;
+  certReqInfo: IPkcs10CertificationRequestInfo;
+  tbsBytes: TCryptoLibByteArray;
+  hashBytes: TCryptoLibByteArray;
+  signer: IECDsaSigner;
+  sigValues: TCryptoLibGenericArray<TBigInteger>;
+  sigBytes: TCryptoLibByteArray;
+  sigAlg: IAlgorithmIdentifier;
+  attrs: IDerTaggedObject;
+begin
+  if not Supports(privateKey, IECPrivateKeyParameters) then
+    raise EArgumentCryptoLibException.Create('Expected IECPrivateKeyParameters');
+  ecPrivKey := privateKey as IECPrivateKeyParameters;
+
+  // Build SubjectPublicKeyInfo from EC public key
+  subjectPKInfo := TSubjectPublicKeyInfo.CreateFromPublicKey(FPublicKey);
+
+  // Build attributes with extensions (must be included in TBS for correct signature)
+  attrs := BuildAttributes;
+
+  // Build CertificationRequestInfo for TBS data (with attributes!)
+  certReqInfo := TPkcs10CertificationRequestInfo.Create(FSubject, subjectPKInfo, attrs);
+
+  // Get DER encoding of the to-be-signed portion
+  tbsBytes := certReqInfo.ToAsn1Object.GetEncoded(TAsn1Encodable.Der);
+
+  // Hash the TBS data
+  System.SetLength(hashBytes, FDigest.GetDigestSize);
+  FDigest.BlockUpdate(tbsBytes, 0, System.Length(tbsBytes));
+  FDigest.DoFinal(hashBytes, 0);
+
+  // Sign using ECDSA with deterministic K (RFC 6979)
+  signer := TECDsaSigner.Create(THMacDsaKCalculator.Create(FDigest) as IHMacDsaKCalculator);
+  signer.Init(True, ecPrivKey);
+  sigValues := signer.GenerateSignature(hashBytes);
+
+  // Encode signature as DER SEQUENCE of two INTEGERs
+  sigBytes := TStandardDsaEncoding.Instance.Encode(
+    ecPrivKey.Parameters.N, sigValues[0], sigValues[1]);
+
+  // Get signature algorithm OID based on digest
+  sigAlg := TAlgorithmIdentifier.Create(GetSignatureAlgorithmOid);
+
+  // Create final CSR - pass certReqInfo directly since it already has attrs
+  Result := TPkcs10CertificationRequest.Create(certReqInfo, sigAlg, TDerBitString.Create(sigBytes));
+end;
+
+{ TEdDSACertificationRequestBuilder }
+
+constructor TEdDSACertificationRequestBuilder.Create;
+begin
+  inherited Create();
+  FEd25519PublicKey := nil;
+end;
+
+function TEdDSACertificationRequestBuilder.SetPublicKey(
+  const publicKey: IAsymmetricKeyParameter): IPkcs10CertificationRequestBuilder;
+begin
+  // Detect key type and store appropriately
+  if Supports(publicKey, IEd25519PublicKeyParameters) then
+  begin
+    FEd25519PublicKey := publicKey as IEd25519PublicKeyParameters;
+    // Store encoded key for SKI computation
+    SetPublicKeyBytes(FEd25519PublicKey.GetEncoded);
+  end
+  else
+    raise EArgumentCryptoLibException.Create('Expected IEd25519PublicKeyParameters');
+  Result := Self;
+end;
+
+function TEdDSACertificationRequestBuilder.Build(
+  const privateKey: IAsymmetricKeyParameter): IPkcs10CertificationRequest;
+var
+  subjectPKInfo: ISubjectPublicKeyInfo;
+  certReqInfo: IPkcs10CertificationRequestInfo;
+  tbsBytes: TCryptoLibByteArray;
+  signer: ISigner;
+  sigBytes: TCryptoLibByteArray;
+  sigAlg: IAlgorithmIdentifier;
+  attrs: IDerTaggedObject;
+begin
+  // Detect key type and handle appropriately
+  if Supports(privateKey, IEd25519PrivateKeyParameters) then
+  begin
+    // Build SubjectPublicKeyInfo from Ed25519 public key
+    subjectPKInfo := TSubjectPublicKeyInfo.CreateFromPublicKey(FEd25519PublicKey);
+
+    // Build attributes with extensions (must be included in TBS for correct signature)
+    attrs := BuildAttributes;
+
+    // Build CertificationRequestInfo for TBS data (with attributes!)
+    certReqInfo := TPkcs10CertificationRequestInfo.Create(FSubject, subjectPKInfo, attrs);
+
+    // Get DER encoding of the to-be-signed portion
+    tbsBytes := certReqInfo.ToAsn1Object.GetEncoded(TAsn1Encodable.Der);
+
+    // Use SignerUtilities to create Ed25519 signer
+    signer := TSignerUtilities.GetSigner('Ed25519');
+    signer.Init(True, privateKey);
+    signer.BlockUpdate(tbsBytes, 0, System.Length(tbsBytes));
+    sigBytes := signer.GenerateSignature();
+
+    // Ed25519 signature algorithm - no parameters per RFC 8410
+    sigAlg := TAlgorithmIdentifier.Create(TEdECObjectIdentifiers.id_Ed25519);
+
+    // Create final CSR - pass certReqInfo directly since it already has attrs
+    Result := TPkcs10CertificationRequest.Create(certReqInfo, sigAlg, TDerBitString.Create(sigBytes));
+  end
+  else
+    raise EArgumentCryptoLibException.Create('Expected IEd25519PrivateKeyParameters');
+end;
+
+end.

+ 156 - 0
CryptoLib/src/Asn1/X509/ClpAlgorithmIdentifier.pas

@@ -0,0 +1,156 @@
+{ *********************************************************************************** }
+{ *                              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 ClpAlgorithmIdentifier;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpAsn1Objects,
+  ClpIAsn1Objects,
+  ClpIAlgorithmIdentifier,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SInvalidAlgorithmIdentifier = 'Invalid AlgorithmIdentifier: %s';
+  SBadSequenceSize = 'Bad Sequence Size: %d';
+
+type
+  /// <summary>
+  /// AlgorithmIdentifier ::= SEQUENCE {
+  ///   algorithm OBJECT IDENTIFIER,
+  ///   parameters ANY DEFINED BY algorithm OPTIONAL
+  /// }
+  /// </summary>
+  TAlgorithmIdentifier = class(TAsn1Encodable, IAlgorithmIdentifier)
+
+  strict private
+  var
+    FAlgorithm: IDerObjectIdentifier;
+    FParameters: IAsn1Encodable;
+
+    function GetAlgorithm: IDerObjectIdentifier;
+    function GetParameters: IAsn1Encodable;
+
+    constructor Create(const seq: IAsn1Sequence); overload;
+
+  public
+    constructor Create(const algorithm: IDerObjectIdentifier); overload;
+    constructor Create(const algorithm: IDerObjectIdentifier;
+      const parameters: IAsn1Encodable); overload;
+
+    function ToAsn1Object(): IAsn1Object; override;
+
+    property Algorithm: IDerObjectIdentifier read GetAlgorithm;
+    property Parameters: IAsn1Encodable read GetParameters;
+
+    class function GetInstance(obj: TObject): IAlgorithmIdentifier; overload;
+      static;
+    class function GetInstance(const obj: IAsn1TaggedObject;
+      explicitly: Boolean): IAlgorithmIdentifier; overload; static;
+  end;
+
+implementation
+
+{ TAlgorithmIdentifier }
+
+constructor TAlgorithmIdentifier.Create(const algorithm: IDerObjectIdentifier);
+begin
+  inherited Create();
+  FAlgorithm := algorithm;
+  FParameters := nil;
+end;
+
+constructor TAlgorithmIdentifier.Create(const algorithm: IDerObjectIdentifier;
+  const parameters: IAsn1Encodable);
+begin
+  inherited Create();
+  FAlgorithm := algorithm;
+  FParameters := parameters;
+end;
+
+constructor TAlgorithmIdentifier.Create(const seq: IAsn1Sequence);
+begin
+  inherited Create();
+  if (seq.Count < 1) or (seq.Count > 2) then
+  begin
+    raise EArgumentCryptoLibException.CreateResFmt(@SBadSequenceSize,
+      [seq.Count]);
+  end;
+
+  FAlgorithm := TDerObjectIdentifier.GetInstance(seq[0] as TAsn1Encodable);
+
+  if seq.Count = 2 then
+  begin
+    FParameters := seq[1] as IAsn1Encodable;
+  end
+  else
+  begin
+    FParameters := nil;
+  end;
+end;
+
+function TAlgorithmIdentifier.GetAlgorithm: IDerObjectIdentifier;
+begin
+  Result := FAlgorithm;
+end;
+
+function TAlgorithmIdentifier.GetParameters: IAsn1Encodable;
+begin
+  Result := FParameters;
+end;
+
+class function TAlgorithmIdentifier.GetInstance(obj: TObject): IAlgorithmIdentifier;
+begin
+  if (obj = nil) or (obj is TAlgorithmIdentifier) then
+  begin
+    Result := obj as TAlgorithmIdentifier;
+    Exit;
+  end;
+
+  if obj is TAsn1Sequence then
+  begin
+    Result := TAlgorithmIdentifier.Create(obj as TAsn1Sequence);
+    Exit;
+  end;
+
+  raise EArgumentCryptoLibException.CreateResFmt(@SInvalidAlgorithmIdentifier,
+    [obj.ToString]);
+end;
+
+class function TAlgorithmIdentifier.GetInstance(const obj: IAsn1TaggedObject;
+  explicitly: Boolean): IAlgorithmIdentifier;
+begin
+  Result := GetInstance(TAsn1Sequence.GetInstance(obj, explicitly) as TAsn1Sequence);
+end;
+
+function TAlgorithmIdentifier.ToAsn1Object: IAsn1Object;
+var
+  v: IAsn1EncodableVector;
+begin
+  v := TAsn1EncodableVector.Create();
+  v.Add(FAlgorithm);
+
+  if FParameters <> nil then
+    v.Add(FParameters);
+
+  Result := TDerSequence.FromVector(v);
+end;
+
+end.

+ 254 - 0
CryptoLib/src/Asn1/X509/ClpSubjectPublicKeyInfo.pas

@@ -0,0 +1,254 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSubjectPublicKeyInfo;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpAsn1Objects,
+  ClpIAsn1Objects,
+  ClpAlgorithmIdentifier,
+  ClpIAlgorithmIdentifier,
+  ClpISubjectPublicKeyInfo,
+  ClpIAsymmetricKeyParameter,
+  ClpIECPublicKeyParameters,
+  ClpIECDomainParameters,
+  ClpX9ObjectIdentifiers,
+  ClpX9ECParameters,
+  ClpIX9ECParameters,
+  ClpECNamedCurveTable,
+  ClpIEd25519PublicKeyParameters,
+  ClpEdECObjectIdentifiers,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SInvalidSubjectPublicKeyInfo = 'Invalid SubjectPublicKeyInfo: %s';
+  SBadSequenceSize = 'Bad Sequence Size: %d';
+  SUnsupportedPublicKeyType = 'Unsupported public key type';
+
+type
+  /// <summary>
+  /// SubjectPublicKeyInfo ::= SEQUENCE {
+  ///   algorithm AlgorithmIdentifier,
+  ///   subjectPublicKey BIT STRING
+  /// }
+  /// </summary>
+  TSubjectPublicKeyInfo = class(TAsn1Encodable, ISubjectPublicKeyInfo)
+
+  strict private
+  var
+    FAlgorithm: IAlgorithmIdentifier;
+    FPublicKeyData: IDerBitString;
+
+    function GetAlgorithm: IAlgorithmIdentifier;
+    function GetPublicKeyData: IDerBitString;
+
+    constructor Create(const seq: IAsn1Sequence); overload;
+
+  public
+    constructor Create(const algorithm: IAlgorithmIdentifier;
+      const publicKey: IDerBitString); overload;
+
+    function ToAsn1Object(): IAsn1Object; override;
+
+    property Algorithm: IAlgorithmIdentifier read GetAlgorithm;
+    property PublicKeyData: IDerBitString read GetPublicKeyData;
+
+    class function GetInstance(obj: TObject): ISubjectPublicKeyInfo; overload;
+      static;
+    class function GetInstance(const obj: IAsn1TaggedObject;
+      explicitly: Boolean): ISubjectPublicKeyInfo; overload; static;
+
+    /// <summary>
+    /// Creates SubjectPublicKeyInfo from a public key.
+    /// Supports ECDSA (IECPublicKeyParameters) and EdDSA (Ed25519).
+    /// For ECDSA, automatically detects named curves and uses compact OID.
+    /// </summary>
+    class function CreateFromPublicKey(
+      const publicKey: IAsymmetricKeyParameter): ISubjectPublicKeyInfo; static;
+
+  strict private
+    /// <summary>
+    /// Finds the named curve OID for the given domain parameters.
+    /// Returns nil if no matching named curve is found.
+    /// </summary>
+    class function FindCurveOid(
+      const domain: IECDomainParameters): IDerObjectIdentifier; static;
+  end;
+
+implementation
+
+{ TSubjectPublicKeyInfo }
+
+constructor TSubjectPublicKeyInfo.Create(const algorithm: IAlgorithmIdentifier;
+  const publicKey: IDerBitString);
+begin
+  inherited Create();
+  FAlgorithm := algorithm;
+  FPublicKeyData := publicKey;
+end;
+
+constructor TSubjectPublicKeyInfo.Create(const seq: IAsn1Sequence);
+begin
+  inherited Create();
+  if seq.Count <> 2 then
+  begin
+    raise EArgumentCryptoLibException.CreateResFmt(@SBadSequenceSize,
+      [seq.Count]);
+  end;
+
+  FAlgorithm := TAlgorithmIdentifier.GetInstance(seq[0] as TObject);
+  FPublicKeyData := TDerBitString.GetInstance(seq[1] as TAsn1Encodable);
+end;
+
+function TSubjectPublicKeyInfo.GetAlgorithm: IAlgorithmIdentifier;
+begin
+  Result := FAlgorithm;
+end;
+
+function TSubjectPublicKeyInfo.GetPublicKeyData: IDerBitString;
+begin
+  Result := FPublicKeyData;
+end;
+
+class function TSubjectPublicKeyInfo.GetInstance(obj: TObject): ISubjectPublicKeyInfo;
+begin
+  if (obj = nil) or (obj is TSubjectPublicKeyInfo) then
+  begin
+    Result := obj as TSubjectPublicKeyInfo;
+    Exit;
+  end;
+
+  if obj is TAsn1Sequence then
+  begin
+    Result := TSubjectPublicKeyInfo.Create(obj as TAsn1Sequence);
+    Exit;
+  end;
+
+  raise EArgumentCryptoLibException.CreateResFmt(@SInvalidSubjectPublicKeyInfo,
+    [obj.ToString]);
+end;
+
+class function TSubjectPublicKeyInfo.GetInstance(const obj: IAsn1TaggedObject;
+  explicitly: Boolean): ISubjectPublicKeyInfo;
+begin
+  Result := GetInstance(TAsn1Sequence.GetInstance(obj, explicitly) as TAsn1Sequence);
+end;
+
+function TSubjectPublicKeyInfo.ToAsn1Object: IAsn1Object;
+var
+  v: IAsn1EncodableVector;
+  algAsn1: IAsn1Object;
+begin
+  algAsn1 := FAlgorithm.ToAsn1Object;
+
+  v := TAsn1EncodableVector.Create();
+  v.Add(algAsn1);
+  v.Add(FPublicKeyData);
+
+  Result := TDerSequence.FromVector(v);
+end;
+
+class function TSubjectPublicKeyInfo.FindCurveOid(
+  const domain: IECDomainParameters): IDerObjectIdentifier;
+var
+  names: TCryptoLibStringArray;
+  name: string;
+  curveParams: IX9ECParameters;
+begin
+  Result := nil;
+  names := TECNamedCurveTable.Names;
+
+  for name in names do
+  begin
+    curveParams := TECNamedCurveTable.GetByName(name);
+    // Compare N (unique per curve, fast BigInteger comparison)
+    if (curveParams <> nil) and domain.N.Equals(curveParams.N) then
+    begin
+      Result := TECNamedCurveTable.GetOid(name);
+      Exit;
+    end;
+  end;
+end;
+
+class function TSubjectPublicKeyInfo.CreateFromPublicKey(
+  const publicKey: IAsymmetricKeyParameter): ISubjectPublicKeyInfo;
+var
+  domain: IECDomainParameters;
+  encodedPoint: TCryptoLibByteArray;
+  ecParams: IX9ECParameters;
+  algId: IAlgorithmIdentifier;
+  pubKeyBits: IDerBitString;
+  ecPublicKey: IECPublicKeyParameters;
+  ed25519Key: IEd25519PublicKeyParameters;
+  encodedKey: TCryptoLibByteArray;
+  curveOid: IDerObjectIdentifier;
+begin
+  // ECDSA keys
+  if Supports(publicKey, IECPublicKeyParameters) then
+  begin
+    ecPublicKey := publicKey as IECPublicKeyParameters;
+    domain := ecPublicKey.Parameters;
+
+    // Try to find named curve OID first (compact representation)
+    curveOid := FindCurveOid(domain);
+
+    if curveOid <> nil then
+    begin
+      // Use named curve OID as parameter
+      algId := TAlgorithmIdentifier.Create(TX9ObjectIdentifiers.IdECPublicKey, curveOid);
+    end
+    else
+    begin
+      // Fall back to explicit parameters for custom/unknown curves
+      ecParams := TX9ECParameters.Create(domain.Curve, domain.G, domain.N,
+        domain.H, domain.GetSeed);
+      algId := TAlgorithmIdentifier.Create(TX9ObjectIdentifiers.IdECPublicKey,
+        ecParams.ToAsn1Object);
+    end;
+
+    // Encode the public key point (uncompressed encoding)
+    encodedPoint := ecPublicKey.Q.GetEncoded(False);
+
+    pubKeyBits := TDerBitString.Create(encodedPoint);
+
+    Result := TSubjectPublicKeyInfo.Create(algId, pubKeyBits);
+  end
+  // Ed25519 keys
+  else if Supports(publicKey, IEd25519PublicKeyParameters) then
+  begin
+    ed25519Key := publicKey as IEd25519PublicKeyParameters;
+
+    // Per RFC 8410: Ed25519 uses id-Ed25519 (1.3.101.112) with no parameters
+    algId := TAlgorithmIdentifier.Create(TEdECObjectIdentifiers.id_Ed25519);
+
+    // Get the raw 32-byte public key encoding
+    encodedKey := ed25519Key.GetEncoded();
+
+    pubKeyBits := TDerBitString.Create(encodedKey);
+
+    Result := TSubjectPublicKeyInfo.Create(algId, pubKeyBits);
+  end
+  else
+    raise EArgumentCryptoLibException.Create(SUnsupportedPublicKeyType);
+end;
+
+end.

+ 336 - 0
CryptoLib/src/Asn1/X509/ClpX500Name.pas

@@ -0,0 +1,336 @@
+{ *********************************************************************************** }
+{ *                              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 ClpX500Name;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  Generics.Collections,
+  ClpAsn1Objects,
+  ClpIAsn1Objects,
+  ClpIX500Name,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SInvalidX500Name = 'Invalid X500Name: %s';
+
+type
+  /// <summary>
+  /// X.500 Object Identifiers for Distinguished Name attributes
+  /// </summary>
+  TX500NameOids = class abstract(TObject)
+  strict private
+  const
+    // Base OID for X.500 attribute types: 2.5.4
+    X500AttrBase: String = '2.5.4';
+    // PKCS#9 base: 1.2.840.113549.1.9
+    Pkcs9Base: String = '1.2.840.113549.1.9';
+
+  class var
+    FIsBooted: Boolean;
+    FCommonName, FOrganization, FOrganizationalUnit, FCountry, FState,
+      FLocality, FSerialNumber, FEmailAddress: IDerObjectIdentifier;
+
+    class function GetCommonName: IDerObjectIdentifier; static; inline;
+    class function GetOrganization: IDerObjectIdentifier; static; inline;
+    class function GetOrganizationalUnit: IDerObjectIdentifier; static; inline;
+    class function GetCountry: IDerObjectIdentifier; static; inline;
+    class function GetState: IDerObjectIdentifier; static; inline;
+    class function GetLocality: IDerObjectIdentifier; static; inline;
+    class function GetSerialNumber: IDerObjectIdentifier; static; inline;
+    class function GetEmailAddress: IDerObjectIdentifier; static; inline;
+
+    class constructor X500NameOids();
+
+  public
+    /// <summary>Common Name (CN) - 2.5.4.3</summary>
+    class property CommonName: IDerObjectIdentifier read GetCommonName;
+    /// <summary>Organization (O) - 2.5.4.10</summary>
+    class property Organization: IDerObjectIdentifier read GetOrganization;
+    /// <summary>Organizational Unit (OU) - 2.5.4.11</summary>
+    class property OrganizationalUnit: IDerObjectIdentifier read GetOrganizationalUnit;
+    /// <summary>Country (C) - 2.5.4.6</summary>
+    class property Country: IDerObjectIdentifier read GetCountry;
+    /// <summary>State/Province (ST) - 2.5.4.8</summary>
+    class property State: IDerObjectIdentifier read GetState;
+    /// <summary>Locality (L) - 2.5.4.7</summary>
+    class property Locality: IDerObjectIdentifier read GetLocality;
+    /// <summary>Serial Number - 2.5.4.5</summary>
+    class property SerialNumber: IDerObjectIdentifier read GetSerialNumber;
+    /// <summary>Email Address - 1.2.840.113549.1.9.1</summary>
+    class property EmailAddress: IDerObjectIdentifier read GetEmailAddress;
+
+    class procedure Boot(); static;
+  end;
+
+type
+  /// <summary>
+  /// X.500 Distinguished Name
+  /// Name ::= SEQUENCE OF RelativeDistinguishedName
+  /// RDN ::= SET OF AttributeTypeAndValue
+  /// AttributeTypeAndValue ::= SEQUENCE { type OID, value ANY }
+  /// </summary>
+  TX500Name = class(TAsn1Encodable, IX500Name)
+
+  strict private
+  var
+    FSeq: IAsn1Sequence;
+
+    constructor Create(const seq: IAsn1Sequence); overload;
+
+  public
+    constructor Create(const rdnSequence: TList<IAsn1Encodable>); overload;
+
+    function ToAsn1Object(): IAsn1Object; override;
+
+    class function GetInstance(obj: TObject): IX500Name; overload; static;
+    class function GetInstance(const obj: IAsn1TaggedObject;
+      explicitly: Boolean): IX500Name; overload; static;
+  end;
+
+type
+  /// <summary>
+  /// Builder for X.500 Distinguished Names
+  /// </summary>
+  TX500NameBuilder = class(TInterfacedObject, IX500NameBuilder)
+  strict private
+  var
+    FRdns: TList<IAsn1Encodable>;
+
+    function CreateRdn(const oid: IDerObjectIdentifier;
+      const value: string): IAsn1Encodable;
+
+  public
+    constructor Create();
+    destructor Destroy(); override;
+
+    function AddRdn(const oid: IDerObjectIdentifier; const value: string): IX500NameBuilder;
+    function AddCommonName(const value: string): IX500NameBuilder;
+    function AddOrganization(const value: string): IX500NameBuilder;
+    function AddOrganizationalUnit(const value: string): IX500NameBuilder;
+    function AddCountry(const value: string): IX500NameBuilder;
+    function AddState(const value: string): IX500NameBuilder;
+    function AddLocality(const value: string): IX500NameBuilder;
+    function AddEmailAddress(const value: string): IX500NameBuilder;
+    function Build: IX500Name;
+  end;
+
+implementation
+
+{ TX500NameOids }
+
+class procedure TX500NameOids.Boot;
+begin
+  if not FIsBooted then
+  begin
+    FCommonName := TDerObjectIdentifier.Create(X500AttrBase + '.3');
+    FOrganization := TDerObjectIdentifier.Create(X500AttrBase + '.10');
+    FOrganizationalUnit := TDerObjectIdentifier.Create(X500AttrBase + '.11');
+    FCountry := TDerObjectIdentifier.Create(X500AttrBase + '.6');
+    FState := TDerObjectIdentifier.Create(X500AttrBase + '.8');
+    FLocality := TDerObjectIdentifier.Create(X500AttrBase + '.7');
+    FSerialNumber := TDerObjectIdentifier.Create(X500AttrBase + '.5');
+    FEmailAddress := TDerObjectIdentifier.Create(Pkcs9Base + '.1');
+
+    FIsBooted := True;
+  end;
+end;
+
+class function TX500NameOids.GetCommonName: IDerObjectIdentifier;
+begin
+  Result := FCommonName;
+end;
+
+class function TX500NameOids.GetOrganization: IDerObjectIdentifier;
+begin
+  Result := FOrganization;
+end;
+
+class function TX500NameOids.GetOrganizationalUnit: IDerObjectIdentifier;
+begin
+  Result := FOrganizationalUnit;
+end;
+
+class function TX500NameOids.GetCountry: IDerObjectIdentifier;
+begin
+  Result := FCountry;
+end;
+
+class function TX500NameOids.GetState: IDerObjectIdentifier;
+begin
+  Result := FState;
+end;
+
+class function TX500NameOids.GetLocality: IDerObjectIdentifier;
+begin
+  Result := FLocality;
+end;
+
+class function TX500NameOids.GetSerialNumber: IDerObjectIdentifier;
+begin
+  Result := FSerialNumber;
+end;
+
+class function TX500NameOids.GetEmailAddress: IDerObjectIdentifier;
+begin
+  Result := FEmailAddress;
+end;
+
+class constructor TX500NameOids.X500NameOids;
+begin
+  TX500NameOids.Boot;
+end;
+
+{ TX500Name }
+
+constructor TX500Name.Create(const seq: IAsn1Sequence);
+begin
+  inherited Create();
+  FSeq := seq;
+end;
+
+constructor TX500Name.Create(const rdnSequence: TList<IAsn1Encodable>);
+var
+  arr: TCryptoLibGenericArray<IAsn1Encodable>;
+  i: Integer;
+begin
+  inherited Create();
+  System.SetLength(arr, rdnSequence.Count);
+  for i := 0 to rdnSequence.Count - 1 do
+  begin
+    arr[i] := rdnSequence[i];
+  end;
+  FSeq := TDerSequence.Create(arr);
+end;
+
+class function TX500Name.GetInstance(obj: TObject): IX500Name;
+begin
+  if (obj = nil) or (obj is TX500Name) then
+  begin
+    Result := obj as TX500Name;
+    Exit;
+  end;
+
+  if obj is TAsn1Sequence then
+  begin
+    Result := TX500Name.Create(obj as TAsn1Sequence);
+    Exit;
+  end;
+
+  raise EArgumentCryptoLibException.CreateResFmt(@SInvalidX500Name,
+    [obj.ToString]);
+end;
+
+class function TX500Name.GetInstance(const obj: IAsn1TaggedObject;
+  explicitly: Boolean): IX500Name;
+begin
+  Result := GetInstance(TAsn1Sequence.GetInstance(obj, explicitly) as TAsn1Sequence);
+end;
+
+function TX500Name.ToAsn1Object: IAsn1Object;
+begin
+  Result := FSeq;
+end;
+
+{ TX500NameBuilder }
+
+constructor TX500NameBuilder.Create;
+begin
+  inherited Create();
+  FRdns := TList<IAsn1Encodable>.Create;
+end;
+
+destructor TX500NameBuilder.Destroy;
+begin
+  FRdns.Free;
+  inherited Destroy();
+end;
+
+function TX500NameBuilder.CreateRdn(const oid: IDerObjectIdentifier;
+  const value: string): IAsn1Encodable;
+var
+  seqV, setV: IAsn1EncodableVector;
+  rdnValue: IDerUtf8String;
+  attrTypeAndValue: IDerSequence;
+begin
+  // Create the UTF8 string value
+  rdnValue := TDerUtf8String.Create(value);
+
+  // AttributeTypeAndValue ::= SEQUENCE { type OID, value ANY }
+  seqV := TAsn1EncodableVector.Create();
+  seqV.Add(oid);
+  seqV.Add(rdnValue);
+  attrTypeAndValue := TDerSequence.FromVector(seqV);
+
+  // RDN ::= SET OF AttributeTypeAndValue
+  setV := TAsn1EncodableVector.Create();
+  setV.Add(attrTypeAndValue);
+  Result := TDerSet.FromVector(setV, False);
+end;
+
+function TX500NameBuilder.AddRdn(const oid: IDerObjectIdentifier;
+  const value: string): IX500NameBuilder;
+begin
+  FRdns.Add(CreateRdn(oid, value));
+  Result := Self;
+end;
+
+function TX500NameBuilder.AddCommonName(const value: string): IX500NameBuilder;
+begin
+  Result := AddRdn(TX500NameOids.CommonName, value);
+end;
+
+function TX500NameBuilder.AddOrganization(const value: string): IX500NameBuilder;
+begin
+  Result := AddRdn(TX500NameOids.Organization, value);
+end;
+
+function TX500NameBuilder.AddOrganizationalUnit(const value: string): IX500NameBuilder;
+begin
+  Result := AddRdn(TX500NameOids.OrganizationalUnit, value);
+end;
+
+function TX500NameBuilder.AddCountry(const value: string): IX500NameBuilder;
+begin
+  Result := AddRdn(TX500NameOids.Country, value);
+end;
+
+function TX500NameBuilder.AddState(const value: string): IX500NameBuilder;
+begin
+  Result := AddRdn(TX500NameOids.State, value);
+end;
+
+function TX500NameBuilder.AddLocality(const value: string): IX500NameBuilder;
+begin
+  Result := AddRdn(TX500NameOids.Locality, value);
+end;
+
+function TX500NameBuilder.AddEmailAddress(const value: string): IX500NameBuilder;
+begin
+  Result := AddRdn(TX500NameOids.EmailAddress, value);
+end;
+
+function TX500NameBuilder.Build: IX500Name;
+begin
+  Result := TX500Name.Create(FRdns);
+end;
+
+end.

+ 39 - 0
CryptoLib/src/Interfaces/ClpIAlgorithmIdentifier.pas

@@ -0,0 +1,39 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIAlgorithmIdentifier;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIAsn1Objects;
+
+type
+  IAlgorithmIdentifier = interface(IAsn1Encodable)
+    ['{D7B8C4E1-8A2F-4B5C-9D3E-1F6A7B8C9D0E}']
+    function GetAlgorithm: IDerObjectIdentifier;
+    function GetParameters: IAsn1Encodable;
+
+    property Algorithm: IDerObjectIdentifier read GetAlgorithm;
+    property Parameters: IAsn1Encodable read GetParameters;
+  end;
+
+implementation
+
+end.

+ 103 - 0
CryptoLib/src/Interfaces/ClpIPkcs10CertificationRequest.pas

@@ -0,0 +1,103 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIPkcs10CertificationRequest;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIAsn1Objects,
+  ClpIAlgorithmIdentifier,
+  ClpISubjectPublicKeyInfo,
+  ClpIX500Name,
+  ClpIAsymmetricKeyParameter,
+  ClpCryptoLibTypes;
+
+type
+  // Forward declaration
+  IPkcs10CertificationRequest = interface;
+
+  /// <summary>
+  /// Interface for PKCS#10 CertificationRequestInfo (to-be-signed portion)
+  /// </summary>
+  IPkcs10CertificationRequestInfo = interface(IAsn1Encodable)
+    ['{C1C8160E-D066-4E12-BE4B-D598AA1B9C87}']
+    function GetVersion: IDerInteger;
+    function GetSubject: IX500Name;
+    function GetSubjectPublicKeyInfo: ISubjectPublicKeyInfo;
+
+    property Version: IDerInteger read GetVersion;
+    property Subject: IX500Name read GetSubject;
+    property SubjectPublicKeyInfo: ISubjectPublicKeyInfo read GetSubjectPublicKeyInfo;
+  end;
+
+  /// <summary>
+  /// Interface for complete PKCS#10 CertificationRequest
+  /// </summary>
+  IPkcs10CertificationRequest = interface(IAsn1Encodable)
+    ['{12920416-C1BF-4B2E-8F67-598FB16D1C30}']
+    function GetCertificationRequestInfo: IPkcs10CertificationRequestInfo;
+    function GetSignatureAlgorithm: IAlgorithmIdentifier;
+    function GetSignature: IDerBitString;
+
+    function GetEncoded(): TCryptoLibByteArray; overload;
+    function GetPemEncoded: string;
+
+    property CertificationRequestInfo: IPkcs10CertificationRequestInfo read GetCertificationRequestInfo;
+    property SignatureAlgorithm: IAlgorithmIdentifier read GetSignatureAlgorithm;
+    property Signature: IDerBitString read GetSignature;
+  end;
+
+  /// <summary>
+  /// Base interface for PKCS#10 Certification Request Builders.
+  /// </summary>
+  IPkcs10CertificationRequestBuilder = interface(IInterface)
+    ['{848CE226-C322-4CC7-A4F5-FD45BC4BE714}']
+    /// <summary>
+    /// Set the subject distinguished name for the CSR.
+    /// </summary>
+    function SetSubject(const subject: IX500Name): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Set the public key. The builder implementation validates the key type.
+    /// </summary>
+    function SetPublicKey(const publicKey: IAsymmetricKeyParameter): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Build the CSR using the provided private key.
+    /// The builder determines the correct signature algorithm based on key type.
+    /// </summary>
+    function Build(const privateKey: IAsymmetricKeyParameter): IPkcs10CertificationRequest;
+
+    /// <summary>
+    /// Add an X.509 extension to the CSR.
+    /// </summary>
+    function AddExtension(const oid: IDerObjectIdentifier; critical: Boolean;
+      const value: IAsn1Encodable): IPkcs10CertificationRequestBuilder;
+
+    /// <summary>
+    /// Add Subject Key Identifier extension (computed from public key).
+    /// Must be called after SetPublicKey.
+    /// </summary>
+    function AddSubjectKeyIdentifier: IPkcs10CertificationRequestBuilder;
+  end;
+
+implementation
+
+end.

+ 41 - 0
CryptoLib/src/Interfaces/ClpISubjectPublicKeyInfo.pas

@@ -0,0 +1,41 @@
+{ *********************************************************************************** }
+{ *                              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 ClpISubjectPublicKeyInfo;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIAsn1Objects,
+  ClpIAlgorithmIdentifier,
+  ClpCryptoLibTypes;
+
+type
+  ISubjectPublicKeyInfo = interface(IAsn1Encodable)
+    ['{59FD4D04-D393-4A72-B6DB-58781CD4D722}']
+    function GetAlgorithm: IAlgorithmIdentifier;
+    function GetPublicKeyData: IDerBitString;
+
+    property Algorithm: IAlgorithmIdentifier read GetAlgorithm;
+    property PublicKeyData: IDerBitString read GetPublicKeyData;
+  end;
+
+implementation
+
+end.

+ 53 - 0
CryptoLib/src/Interfaces/ClpIX500Name.pas

@@ -0,0 +1,53 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIX500Name;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIAsn1Objects;
+
+type
+  /// <summary>
+  /// Interface for X.500 Distinguished Name
+  /// </summary>
+  IX500Name = interface(IAsn1Encodable)
+    ['{3216F2D5-BA2E-42E4-B439-F550D742F880}']
+  end;
+
+  /// <summary>
+  /// Builder interface for constructing X.500 Names
+  /// </summary>
+  IX500NameBuilder = interface
+    ['{B16CEFF4-EA57-43DC-A9F7-E01456798C82}']
+    function AddRdn(const oid: IDerObjectIdentifier; const value: string): IX500NameBuilder;
+    function AddCommonName(const value: string): IX500NameBuilder;
+    function AddOrganization(const value: string): IX500NameBuilder;
+    function AddOrganizationalUnit(const value: string): IX500NameBuilder;
+    function AddCountry(const value: string): IX500NameBuilder;
+    function AddState(const value: string): IX500NameBuilder;
+    function AddLocality(const value: string): IX500NameBuilder;
+    function AddEmailAddress(const value: string): IX500NameBuilder;
+    function Build: IX500Name;
+  end;
+
+implementation
+
+end.

+ 9 - 1
CryptoLib/src/Packages/Delphi/CryptoLib4PascalPackage.dpk

@@ -393,6 +393,14 @@ contains
   ClpIMultipliers in '..\..\Interfaces\ClpIMultipliers.pas',
   ClpECCompUtilities in '..\..\Math\EC\ClpECCompUtilities.pas',
   ClpIKMac in '..\..\Interfaces\ClpIKMac.pas',
-  ClpKMac in '..\..\Crypto\Macs\ClpKMac.pas';
+  ClpKMac in '..\..\Crypto\Macs\ClpKMac.pas',
+  ClpAlgorithmIdentifier in '..\..\Asn1\X509\ClpAlgorithmIdentifier.pas',
+  ClpIAlgorithmIdentifier in '..\..\Interfaces\ClpIAlgorithmIdentifier.pas',
+  ClpSubjectPublicKeyInfo in '..\..\Asn1\X509\ClpSubjectPublicKeyInfo.pas',
+  ClpISubjectPublicKeyInfo in '..\..\Interfaces\ClpISubjectPublicKeyInfo.pas',
+  ClpX500Name in '..\..\Asn1\X509\ClpX500Name.pas',
+  ClpIX500Name in '..\..\Interfaces\ClpIX500Name.pas',
+  ClpPkcs10CertificationRequest in '..\..\Asn1\Pkcs\ClpPkcs10CertificationRequest.pas',
+  ClpIPkcs10CertificationRequest in '..\..\Interfaces\ClpIPkcs10CertificationRequest.pas';
 
 end.

+ 33 - 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="2"/>
-    <Files Count="360">
+    <Files Count="368">
       <Item1>
         <Filename Value="..\..\Asn1\ClpOidTokenizer.pas"/>
         <UnitName Value="ClpOidTokenizer"/>
@@ -1467,6 +1467,38 @@ Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the devel
         <Filename Value="..\..\Math\EC\Multiplier\ClpMultipliers.pas"/>
         <UnitName Value="ClpMultipliers"/>
       </Item360>
+      <Item361>
+        <Filename Value="..\..\Asn1\X509\ClpAlgorithmIdentifier.pas"/>
+        <UnitName Value="ClpAlgorithmIdentifier"/>
+      </Item361>
+      <Item362>
+        <Filename Value="..\..\Interfaces\ClpIAlgorithmIdentifier.pas"/>
+        <UnitName Value="ClpIAlgorithmIdentifier"/>
+      </Item362>
+      <Item363>
+        <Filename Value="..\..\Asn1\X509\ClpSubjectPublicKeyInfo.pas"/>
+        <UnitName Value="ClpSubjectPublicKeyInfo"/>
+      </Item363>
+      <Item364>
+        <Filename Value="..\..\Interfaces\ClpISubjectPublicKeyInfo.pas"/>
+        <UnitName Value="ClpISubjectPublicKeyInfo"/>
+      </Item364>
+      <Item365>
+        <Filename Value="..\..\Asn1\X509\ClpX500Name.pas"/>
+        <UnitName Value="ClpX500Name"/>
+      </Item365>
+      <Item366>
+        <Filename Value="..\..\Interfaces\ClpIX500Name.pas"/>
+        <UnitName Value="ClpIX500Name"/>
+      </Item366>
+      <Item367>
+        <Filename Value="..\..\Asn1\Pkcs\ClpPkcs10CertificationRequest.pas"/>
+        <UnitName Value="ClpPkcs10CertificationRequest"/>
+      </Item367>
+      <Item368>
+        <Filename Value="..\..\Interfaces\ClpIPkcs10CertificationRequest.pas"/>
+        <UnitName Value="ClpIPkcs10CertificationRequest"/>
+      </Item368>
     </Files>
     <RequiredPkgs Count="3">
       <Item1>

+ 4 - 1
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas

@@ -126,7 +126,10 @@ uses
   ClpScalarSplitParameters, ClpIGlvTypeAParameters, ClpIGlvTypeAEndomorphism, 
   ClpIScaleXNegateYPointMap, ClpIScaleYNegateXPointMap, 
   ClpIScalarSplitParameters, ClpECCompUtilities, ClpValidityPreCompInfo, 
-  ClpIValidityPreCompInfo, ClpKMac, ClpIKMac, ClpMultipliers;
+  ClpIValidityPreCompInfo, ClpKMac, ClpIKMac, ClpMultipliers, 
+  ClpAlgorithmIdentifier, ClpIAlgorithmIdentifier, ClpSubjectPublicKeyInfo, 
+  ClpISubjectPublicKeyInfo, ClpX500Name, ClpIX500Name, 
+  ClpPkcs10CertificationRequest, ClpIPkcs10CertificationRequest;
 
 implementation