Skip to content

Commit

Permalink
decode RFC 5915 Elliptic Curve key pair alternate format
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaud Bouchez committed May 17, 2024
1 parent e5cd81b commit dcedffe
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 30 deletions.
87 changes: 58 additions & 29 deletions src/crypt/mormot.crypt.secure.pas
Original file line number Diff line number Diff line change
Expand Up @@ -3288,7 +3288,10 @@ function EccPrivKeyToSeq(cka: TCryptKeyAlgo; const rawecc: RawByteString): RawBy

/// raw function to decode a PKCS#8 PrivateKeyInfo into its raw binary
// - e.g. as generated by OpenSSL
function SeqToEccPrivKey(cka: TCryptKeyAlgo; const seq: RawByteString): RawByteString;
// - is also able to decode RFC 5915 Elliptic Curve key pair alternate format,
// and its optional public key field
function SeqToEccPrivKey(cka: TCryptKeyAlgo; const seq: RawByteString;
rfcpub: PRawByteString = nil): RawByteString;

/// raw function to decode a specific PKCS#8 PublicKeyInfo into its raw binary
// - e.g. as generated by OpenSSL or X509PubKeyToDer()
Expand Down Expand Up @@ -9132,41 +9135,67 @@ function EccPrivKeyToSeq(
FillZero(oct);
end;

function SeqToEccPrivKey(cka: TCryptKeyAlgo; const seq: RawByteString): RawByteString;
function SeqToEccPrivKey(cka: TCryptKeyAlgo; const seq: RawByteString;
rfcpub: PRawByteString): RawByteString;
var
oid, oct, key: RawByteString;
pos, posoct, vt: integer;
pos, posoct, vt, vers: integer;
begin
result := '';
// PKCS#8 sequence decoding
if rfcpub <> nil then
rfcpub^ := '';// initial sequence decoding
pos := 1;
if (AsnNext(pos, seq) <> ASN1_SEQ) or
(AsnNextInteger(pos, seq, vt) <> 0) or // version
(vt <> ASN1_INT) or
(AsnNext(pos, seq) <> ASN1_SEQ) or // privateKeyAlgorithm
(AsnNext(pos, seq, @oid) <> ASN1_OBJID) then
exit;
// CkaToSeq() decoding
case cka of
ckaEcc256 .. ckaEcc256k:
if (oid <> ASN1_OID_X962_PUBLICKEY) or
(AsnNext(pos, seq, @oid) <> ASN1_OBJID) then
exit;
ckaEdDSA:
;
else
exit; // this function is dedicated to ECC
end;
if oid <> CKA_OID[cka] then
if AsnNext(pos, seq) <> ASN1_SEQ then
exit;
// private key raw binary extraction
posoct := 1;
if (AsnNextRaw(pos, seq, oct) = ASN1_OCTSTR) and // privateKey
(AsnNext(posoct, oct{%H-}) = ASN1_SEQ) and
(AsnNext(posoct, oct) = ASN1_INT) and
(AsnNextRaw(posoct, oct, key) = ASN1_OCTSTR) then
result := key;
vers := AsnNextInteger(pos, seq, vt);
if vt = ASN1_INT then
case vers of
0: // PKCS#8 format
begin
if (AsnNext(pos, seq) <> ASN1_SEQ) or // privateKeyAlgorithm
(AsnNext(pos, seq, @oid) <> ASN1_OBJID) then
exit;
// CkaToSeq() decoding
case cka of
ckaEcc256 .. ckaEcc256k:
if (oid <> ASN1_OID_X962_PUBLICKEY) or
(AsnNext(pos, seq, @oid) <> ASN1_OBJID) then
exit;
ckaEdDSA:
;
else
exit; // this function is dedicated to ECC
end;
if oid <> CKA_OID[cka] then
exit;
// private key raw binary extraction
posoct := 1;
if (AsnNextRaw(pos, seq, oct) = ASN1_OCTSTR) and // privateKey
(AsnNext(posoct, oct{%H-}) = ASN1_SEQ) and
(AsnNext(posoct, oct) = ASN1_INT) and
(AsnNextRaw(posoct, oct, key) = ASN1_OCTSTR) then
result := key;
end;
1: // https://www.rfc-editor.org/rfc/rfc5915 format
if (AsnNextRaw(pos, seq, key) = ASN1_OCTSTR) then // privateKey
begin
vt := AsnNext(pos, seq);
if vt = ASN1_NULL then
result := key // just privateKey, without optional constructed fields
else if (vt = ASN1_CTC0) and // [0] ECparameters (optional)
(AsnNext(pos, seq, @oid) = ASN1_OBJID) and
(oid = CKA_OID[cka]) then
begin
result := key;
if (rfcpub <> nil) and // [1] publicKey (optional)
(AsnNext(pos, seq) = ASN1_CTC1) and
(AsnNextRaw(pos, seq, key) = ASN1_BITSTR) then
rfcpub^ := key;
end;
end;
end;
FillZero(oct);
FillZero(key);
end;

function SeqToEccPubKey(cka: TCryptKeyAlgo; const seq: RawByteString): RawByteString;
Expand Down
2 changes: 1 addition & 1 deletion src/mormot.commit.inc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
'2.2.7517'
'2.2.7518'

0 comments on commit dcedffe

Please sign in to comment.