Skip to content

Commit 13febe7

Browse files
authored
Add Certificate Dispatchers (ecdsa384, rsasha512, rsa 3072, ecdsa256) (#30)
* add ecdsa384 * add rsasha512 * add rsa 3072 * add ecdsa256 * fix test * update changelog
1 parent 454dbe8 commit 13febe7

File tree

16 files changed

+292
-42
lines changed

16 files changed

+292
-42
lines changed

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
# Changelog
22

3+
## [0.1.6]
4+
5+
* Added new algorithms:
6+
1. **Certificate dispatchers**
7+
8+
```solidity
9+
C_RSA_SHA2_3072 = keccak256("C_RSA_3072");
10+
C_RSA_SHA512_4096 = keccak256("C_RSA_SHA512_4096");
11+
C_ECDSA_SECP256R1_SHA1_256 = keccak256("C_ECDSA_SECP256R1_SHA1_256");
12+
```
13+
314
## [0.1.5]
415
16+
517
* Upgraded `StateKeeper` and `Registration2` to be Ownable + TSS. Ownable changes do not require Merkle Proof checks.
618
* Added new algorithms:
719
1. **Certificate dispatchers**
@@ -12,7 +24,6 @@
1224
```
1325
1426
2. **Passport verifiers**
15-
1627
1728
```solidity
1829
Z_PER_PASSPORT_2_256_3_6_336_264_1_2448_3_256 = keccak256("Z_PER_PASSPORT_2_256_3_6_336_264_1_2448_3_256");
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.21;
3+
4+
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
5+
6+
import {ECDSA256} from "@solarity/solidity-lib/libs/crypto/ECDSA256.sol";
7+
8+
import {ICertificateSigner} from "../../interfaces/signers/ICertificateSigner.sol";
9+
10+
import {SHA1} from "../../utils/SHA1.sol";
11+
12+
contract CECDSA256Signer is ICertificateSigner, Initializable {
13+
using ECDSA256 for *;
14+
using SHA1 for *;
15+
16+
enum Curve {
17+
secp256r1
18+
}
19+
20+
enum HF {
21+
sha1
22+
}
23+
24+
ECDSA256.Parameters private _secp256r1CurveParams =
25+
ECDSA256.Parameters({
26+
a: 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC,
27+
b: 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B,
28+
gx: 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296,
29+
gy: 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5,
30+
p: 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF,
31+
n: 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551,
32+
lowSmax: 0x7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8
33+
});
34+
35+
Curve public curve;
36+
HF public hashFunction;
37+
38+
function __CECDSA256Signer_init(Curve curve_, HF hashFunction_) external initializer {
39+
curve = curve_;
40+
hashFunction = hashFunction_;
41+
}
42+
43+
function verifyICAOSignature(
44+
bytes memory x509SignedAttributes_,
45+
bytes memory icaoMemberSignature_,
46+
bytes memory icaoMemberKey_
47+
) external view returns (bool) {
48+
ECDSA256.Parameters memory curveParams_;
49+
function(bytes memory) internal view returns (bytes32) hasher_;
50+
51+
if (curve == Curve.secp256r1) {
52+
curveParams_ = _secp256r1CurveParams;
53+
}
54+
55+
if (hashFunction == HF.sha1) {
56+
hasher_ = _sha1;
57+
}
58+
59+
return
60+
curveParams_.verify(
61+
hasher_(x509SignedAttributes_),
62+
icaoMemberSignature_,
63+
icaoMemberKey_
64+
);
65+
}
66+
67+
function _sha1(bytes memory message) internal pure returns (bytes32) {
68+
return bytes32(message.sha1()) >> 96;
69+
}
70+
}

contracts/certificate/signers/CECDSA384Signer.sol

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ contract CECDSA384Signer is ICertificateSigner, Initializable {
1313
using ECDSA384 for *;
1414
using SHA384 for *;
1515

16+
enum Curve {
17+
secp384r1,
18+
brainpoolP384r1
19+
}
20+
21+
enum HF {
22+
sha256,
23+
sha384
24+
}
25+
1626
ECDSA384.Parameters internal _secp384r1CurveParams =
1727
ECDSA384.Parameters({
1828
a: hex"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc",
@@ -35,12 +45,12 @@ contract CECDSA384Signer is ICertificateSigner, Initializable {
3545
lowSmax: hex"465c8f41519c369407aeb7bf287320ef8a97b884f6aa2b598f8b3736560212d3e79d5b57b5bfe1881dc41901748232b2"
3646
});
3747

38-
bool public isSecp;
39-
bool public isSha2;
48+
Curve public curve;
49+
HF public hashFunction;
4050

41-
function __CECDSA384Signer_init(bool isSecp_, bool isSha2_) external initializer {
42-
isSecp = isSecp_;
43-
isSha2 = isSha2_;
51+
function __CECDSA384Signer_init(Curve curve_, HF hashFunction_) external initializer {
52+
curve = curve_;
53+
hashFunction = hashFunction_;
4454
}
4555

4656
function verifyICAOSignature(
@@ -51,15 +61,15 @@ contract CECDSA384Signer is ICertificateSigner, Initializable {
5161
ECDSA384.Parameters memory curveParams_;
5262
function(bytes memory) internal view returns (bytes memory) hasher_;
5363

54-
if (isSecp) {
64+
if (curve == Curve.secp384r1) {
5565
curveParams_ = _secp384r1CurveParams;
56-
} else {
66+
} else if (curve == Curve.brainpoolP384r1) {
5767
curveParams_ = _brainpoolP384r1CurveParams;
5868
}
5969

60-
if (isSha2) {
70+
if (hashFunction == HF.sha256) {
6171
hasher_ = _sha2;
62-
} else {
72+
} else if (hashFunction == HF.sha384) {
6373
hasher_ = SHA384.sha384;
6474
}
6575

contracts/certificate/signers/CRSAPSSSigner.sol

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,17 @@ import {SHA512} from "../../utils/SHA512.sol";
1212
contract CRSAPSSSigner is ICertificateSigner, Initializable {
1313
using RSASSAPSS for *;
1414

15+
enum HF {
16+
sha256,
17+
sha512
18+
}
19+
1520
uint256 public exponent; // RSAPSS exponent
16-
bool public isSha2; // hash function switcher, true - sha2, false - sha512
21+
HF public hashFunction; // hash function switcher
1722

18-
function __CRSAPSSSigner_init(uint256 exponent_, bool isSha2_) external initializer {
23+
function __CRSAPSSSigner_init(uint256 exponent_, HF hashFunction_) external initializer {
1924
exponent = exponent_;
20-
isSha2 = isSha2_;
25+
hashFunction = hashFunction_;
2126
}
2227

2328
/**
@@ -30,9 +35,9 @@ contract CRSAPSSSigner is ICertificateSigner, Initializable {
3035
) external view override returns (bool) {
3136
RSASSAPSS.Parameters memory params_;
3237

33-
if (isSha2) {
38+
if (hashFunction == HF.sha256) {
3439
params_ = RSASSAPSS.Parameters({hashLength: 32, saltLength: 32, hasher: _sha2});
35-
} else {
40+
} else if (hashFunction == HF.sha512) {
3641
params_ = RSASSAPSS.Parameters({
3742
hashLength: 64,
3843
saltLength: 64,

contracts/certificate/signers/CRSASigner.sol

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,31 @@ import {ICertificateSigner} from "../../interfaces/signers/ICertificateSigner.so
77

88
import {RSA} from "../../utils/RSA.sol";
99
import {SHA1} from "../../utils/SHA1.sol";
10+
import {SHA512} from "../../utils/SHA512.sol";
1011

1112
contract CRSASigner is ICertificateSigner, Initializable {
1213
using RSA for bytes;
1314
using SHA1 for bytes;
15+
using SHA512 for bytes;
16+
17+
enum HF {
18+
sha1,
19+
sha256,
20+
sha512
21+
}
1422

1523
uint256 public exponent; // RSA exponent
16-
bool public isSha1; // hash function switcher, true - sha1, false - sha2
24+
HF public hashFunction; // hash function switcher
1725

18-
function __CRSASigner_init(uint256 exponent_, bool isSha1_) external initializer {
26+
function __CRSASigner_init(uint256 exponent_, HF hashFunction_) external initializer {
1927
exponent = exponent_;
20-
isSha1 = isSha1_;
28+
hashFunction = hashFunction_;
2129
}
2230

2331
/**
2432
* @notice Verifies ICAO member RSA signature of the X509 certificate SA.
2533
*
34+
* The last 64 bytes of the decrypted signature is a SHA512 hash of the certificate signed attributes
2635
* The last 32 bytes of the decrypted signature is a SHA256 hash of the certificate signed attributes
2736
* The last 20 bytes of the decrypted signature is a SHA1 hash of the certificate signed attributes
2837
*/
@@ -31,22 +40,40 @@ contract CRSASigner is ICertificateSigner, Initializable {
3140
bytes memory icaoMemberSignature_,
3241
bytes memory icaoMemberKey_
3342
) external view override returns (bool) {
34-
bytes memory x509SAHash = isSha1
35-
? abi.encodePacked(x509SignedAttributes_.sha1())
36-
: abi.encodePacked(sha256(x509SignedAttributes_));
37-
3843
bytes memory decrypted_ = icaoMemberSignature_.decrypt(
3944
abi.encodePacked(exponent),
4045
icaoMemberKey_
4146
);
4247

48+
bytes32 x509SAHash;
4349
bytes32 decryptedX509SAHash_;
44-
uint256 offset_ = isSha1 ? 12 : 0; // offset for sha1 or sha2
4550

46-
assembly {
47-
decryptedX509SAHash_ := mload(add(add(decrypted_, mload(decrypted_)), offset_)) // load the last 32 or 20 bytes (depends on hash function)
51+
if (hashFunction == HF.sha1) {
52+
x509SAHash = x509SignedAttributes_.sha1();
53+
54+
assembly {
55+
decryptedX509SAHash_ := shl(
56+
96,
57+
shr(96, mload(add(add(decrypted_, mload(decrypted_)), 12)))
58+
) // load last 20 bytes
59+
}
60+
} else if (hashFunction == HF.sha256) {
61+
x509SAHash = sha256(x509SignedAttributes_);
62+
63+
assembly {
64+
decryptedX509SAHash_ := mload(add(decrypted_, mload(decrypted_))) // load last 32 bytes
65+
}
66+
} else if (hashFunction == HF.sha512) {
67+
x509SAHash = keccak256(x509SignedAttributes_.sha512());
68+
69+
assembly {
70+
mstore(0, mload(sub(add(decrypted_, mload(decrypted_)), 32))) // load prelast 32 bytes
71+
mstore(32, mload(add(decrypted_, mload(decrypted_)))) // load last 32 bytes
72+
73+
decryptedX509SAHash_ := keccak256(0, 64) // calculate a hash for quick comparison
74+
}
4875
}
4976

50-
return bytes32(x509SAHash) == decryptedX509SAHash_;
77+
return x509SAHash == decryptedX509SAHash_;
5178
}
5279
}

deploy/10_setup.migration.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,21 @@ import {
5959

6060
import {
6161
C_RSA_SHA1_2048,
62-
C_RSA_SHA2_2048,
6362
C_RSA_SHA1_4096,
63+
C_RSA_SHA2_2048,
64+
C_RSA_SHA2_3072,
6465
C_RSA_SHA2_4096,
66+
C_RSA_SHA512_4096,
6567
C_RSAPSS_SHA2_2048,
6668
C_RSAPSS_SHA2_4096,
6769
C_RSAPSS_SHA512_2048,
6870
C_RSAPSS_SHA512_4096,
71+
C_ECDSA_SECP256R1_SHA1_256,
6972
C_ECDSA_SECP384R1_SHA2_512,
7073
C_ECDSA_SECP384R1_SHA384_512,
7174
C_ECDSA_BRAINPOOLP384R1_SHA2_512,
7275
C_ECDSA_BRAINPOOLP384R1_SHA384_512,
76+
C_ECDSA_BRAINPOOLP384R1_SHA384_768,
7377
C_ECDSA_BRAINPOOLP512R1_SHA512_1024,
7478
P_ECDSA_SHA1_2704,
7579
P_NO_AA,
@@ -138,7 +142,9 @@ export = async (deployer: Deployer) => {
138142
const cRsa4096Sha1Dispatcher = await deployer.deployed(CRSADispatcher__factory, "CRSADispatcher SHA1 512");
139143
const cRsa2048Sha1Dispatcher = await deployer.deployed(CRSADispatcher__factory, "CRSADispatcher SHA1 256");
140144
const cRsa4096Sha2Dispatcher = await deployer.deployed(CRSADispatcher__factory, "CRSADispatcher SHA2 512");
145+
const cRsa3072Sha2Dispatcher = await deployer.deployed(CRSADispatcher__factory, "CRSADispatcher SHA2 384");
141146
const cRsa2048Sha2Dispatcher = await deployer.deployed(CRSADispatcher__factory, "CRSADispatcher SHA2 256");
147+
const cRsa4096Sha512Dispatcher = await deployer.deployed(CRSADispatcher__factory, "CRSADispatcher SHA512 512");
142148

143149
const cRsaPss2048Sha2Dispatcher = await deployer.deployed(
144150
CRSADispatcher__factory,
@@ -157,6 +163,11 @@ export = async (deployer: Deployer) => {
157163
"CRSAPSSDispatcher SHA512 65537 512",
158164
);
159165

166+
const cEcdsaSecp256r1256Sha1Dispatcher = await deployer.deployed(
167+
CECDSADispatcher__factory,
168+
"CECDSADispatcher SECP256 SHA1 64",
169+
);
170+
160171
const cEcdsaSecp384r1512Sha2Dispatcher = await deployer.deployed(
161172
CECDSADispatcher__factory,
162173
"CECDSADispatcher SECP384 SHA2 64",
@@ -173,6 +184,10 @@ export = async (deployer: Deployer) => {
173184
CECDSADispatcher__factory,
174185
"CECDSADispatcher brainpoolP384r1 SHA384 64",
175186
);
187+
const cEcdsaBrainpoolP384r1768Sha384Dispatcher = await deployer.deployed(
188+
CECDSADispatcher__factory,
189+
"CECDSADispatcher brainpoolP384r1 SHA384 96",
190+
);
176191
const cEcdsaBrainpoolP512r11024Sha512Dispatcher = await deployer.deployed(
177192
CECDSADispatcher__factory,
178193
"CECDSADispatcher brainpoolP512r1 SHA512 128",
@@ -321,13 +336,19 @@ export = async (deployer: Deployer) => {
321336
await registration.mockAddCertificateDispatcher(C_RSA_SHA1_4096, await cRsa4096Sha1Dispatcher.getAddress());
322337
await registration.mockAddCertificateDispatcher(C_RSA_SHA1_2048, await cRsa2048Sha1Dispatcher.getAddress());
323338
await registration.mockAddCertificateDispatcher(C_RSA_SHA2_4096, await cRsa4096Sha2Dispatcher.getAddress());
339+
await registration.mockAddCertificateDispatcher(C_RSA_SHA2_3072, await cRsa3072Sha2Dispatcher.getAddress());
324340
await registration.mockAddCertificateDispatcher(C_RSA_SHA2_2048, await cRsa2048Sha2Dispatcher.getAddress());
341+
await registration.mockAddCertificateDispatcher(C_RSA_SHA512_4096, await cRsa4096Sha512Dispatcher.getAddress());
325342

326343
await registration.mockAddCertificateDispatcher(C_RSAPSS_SHA2_2048, await cRsaPss2048Sha2Dispatcher.getAddress());
327344
await registration.mockAddCertificateDispatcher(C_RSAPSS_SHA2_4096, await cRsaPss4096Sha2Dispatcher.getAddress());
328345
await registration.mockAddCertificateDispatcher(C_RSAPSS_SHA512_2048, await cRsaPss2048Sha512Dispatcher.getAddress());
329346
await registration.mockAddCertificateDispatcher(C_RSAPSS_SHA512_4096, await cRsaPss4096Sha512Dispatcher.getAddress());
330347

348+
await registration.mockAddCertificateDispatcher(
349+
C_ECDSA_SECP256R1_SHA1_256,
350+
await cEcdsaSecp256r1256Sha1Dispatcher.getAddress(),
351+
);
331352
await registration.mockAddCertificateDispatcher(
332353
C_ECDSA_SECP384R1_SHA2_512,
333354
await cEcdsaSecp384r1512Sha2Dispatcher.getAddress(),
@@ -344,6 +365,10 @@ export = async (deployer: Deployer) => {
344365
C_ECDSA_BRAINPOOLP384R1_SHA384_512,
345366
await cEcdsaBrainpoolP384r1512Sha384Dispatcher.getAddress(),
346367
);
368+
await registration.mockAddCertificateDispatcher(
369+
C_ECDSA_BRAINPOOLP384R1_SHA384_768,
370+
await cEcdsaBrainpoolP384r1768Sha384Dispatcher.getAddress(),
371+
);
347372
await registration.mockAddCertificateDispatcher(
348373
C_ECDSA_BRAINPOOLP512R1_SHA512_1024,
349374
await cEcdsaBrainpoolP512r11024Sha512Dispatcher.getAddress(),

deploy/2_registration.migration.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,21 @@ export = async (deployer: Deployer) => {
3030
await deployCRSADispatcher(deployer, "SHA1", "65537", "512", "0x0282020100");
3131
await deployCRSADispatcher(deployer, "SHA1", "65537", "256", "0x0282010100");
3232
await deployCRSADispatcher(deployer, "SHA2", "65537", "512", "0x0282020100");
33+
await deployCRSADispatcher(deployer, "SHA2", "65537", "384", "0x0282018100");
3334
await deployCRSADispatcher(deployer, "SHA2", "65537", "256", "0x0282010100");
35+
await deployCRSADispatcher(deployer, "SHA512", "65537", "512", "0x0282020100");
3436

3537
await deployCRSAPSSDispatcher(deployer, "SHA2", "65537", "256", "0x0282010100");
3638
await deployCRSAPSSDispatcher(deployer, "SHA2", "65537", "512", "0x0282020100");
3739
await deployCRSAPSSDispatcher(deployer, "SHA512", "65537", "256", "0x0282010100");
3840
await deployCRSAPSSDispatcher(deployer, "SHA512", "65537", "512", "0x0282020100");
3941

42+
await deployCECDSADispatcher(deployer, "SECP256", "SHA1", "64", "0x03420004");
4043
await deployCECDSADispatcher(deployer, "SECP384", "SHA2", "64", "0x03420004");
4144
await deployCECDSADispatcher(deployer, "SECP384", "SHA384", "64", "0x03420004");
4245
await deployCECDSADispatcher(deployer, "brainpoolP384r1", "SHA2", "64", "0x03420004");
4346
await deployCECDSADispatcher(deployer, "brainpoolP384r1", "SHA384", "64", "0x03420004");
47+
await deployCECDSADispatcher(deployer, "brainpoolP384r1", "SHA384", "96", "0x03620004");
4448
await deployCECDSADispatcher(deployer, "brainpoolP512r1", "SHA512", "128", "0x0381820004");
4549

4650
await deployPRSASHA2688Dispatcher(deployer, "65537", "SHA1");

0 commit comments

Comments
 (0)