merge dev

This commit is contained in:
ayman
2025-01-06 12:52:59 +05:30
183 changed files with 8008 additions and 9548 deletions

View File

@@ -23,7 +23,7 @@
"elliptic": "^6.5.5",
"fs": "^0.0.1-security",
"js-sha1": "^0.7.0",
"js-sha256": "^0.10.1",
"js-sha256": "^0.11.0",
"js-sha512": "^0.9.0",
"json-to-ts": "^2.1.0",
"jsrsasign": "^11.1.0",

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIFCTCCAvGgAwIBAgIUU3HXu3HEmJlh+Cqpae1jkw1k5GAwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJTW9jayBDU0NBMB4XDTI1MDEwNTEyMTIxMFoXDTM1MDEw
MzEyMTIxMFowFDESMBAGA1UEAwwJTW9jayBDU0NBMIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEA0m44QfCCuLqxmMJaBfmDK3OdXKN3eNJiB/fcJkTtMinr
beXJgs0GXyS2HJF3LEw5s9yQQlQ+Va6B5+TOWoPdT/pOTJkd6i8/61pkqWZl2CPm
Aglmn50kAb4MFkJlz0/JJg9aFPw8FBITKf+v2GVd3FZV3Tk7ADzJeOaaBsfEaAg2
Q/XFwavDDrfAOhQL0gzrJuiSUwywPt1j6R3imY6Ba2bss0byjddaHdVaKgXJL2pJ
nKXowrB/Q8mDN2NcGgQrGVDU+kUPz3Rq7YkUg0VEzg1PkqgW1pGMnYpLMkUQXBKl
WbsVudmEHKP3ENessZzrB/jbN8SkNv5bZINKx7YzCR6129FX1rpVQ7k8eBt32BG+
8h2gq3mYt4zf3Ge1ii2StnHryjC/XXC/50lhNfHEElT96PaoYhdzdGM5Ao8+NJxi
BRgvE6uTQjGqkIg4qdsHLt2G4FLpV+ieSbSbSTNvR3eY+lJDduCnBbqJhjoiTtAf
w1bSYL06D+gvS1QCqBMGj8dBqGvoI8K0OJYUmkJWBA6MjLKWtRoI0bjOyONWWWjD
HdcHZlYaAN3nfgDNDEsJMnvG/iVWTpOpGd9q9tkfBaYbZVTEUMWY0ME6rtyczr3c
++ix6TIt6hbTFdqmqWgOVBZxHjnNgcw3HMDgnwGCYp4J8BGqVuuw5eTU3Rqy37cC
AwEAAaNTMFEwHQYDVR0OBBYEFNhpgbT96UUf2f2mxDGchFw8sqVqMB8GA1UdIwQY
MBaAFNhpgbT96UUf2f2mxDGchFw8sqVqMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggIBAFZogQWujEVZa10UDxM1R8JBxgtzkFDn2SqkxZv9ht1Ux4BH
4EUpFgeRJoOvV9+j4oMGZFfPkaoszbyXhnwHRwlwIbBOXHjS7GJNQI5yMjD+BApA
f56bW/jZ+Sk7xEATQyLDllE9e9YXAsTQ8OsWSdJom4Ka7x3TVKHzqtySzlY8SJaE
mnaZ3TZmGNH8azzt9imlZuRbJQdAI28RQChAMLQM80NXHJTneV5Maeo+fQjyB4Uv
haRDgNreIarPLuuaVsKnPPcPOiZfzqeAeJEaEGwYORrYWrQERqNvcvOW7bAh/JoO
fSTPdgtx3lXcUhgulqseTdddbeCkvmHgbCEjzh7SqFDRdUuL3gNs4fAE9K7z9sA5
g7F2q9kgYDO0b/KvKCh9eWlnotEHd67VMeoCDF183vy0ALeYxdGamt3wuglLUX5v
LhwZ70IzHTHnQ9ctQTQ6dohcgwK4wr0NjhEjC7OAHMRfeF5FQH01Dfs0F7c4gJ6N
HjLmTmceeabvy/LJBlDKrDUg34kEbZ9b+oJoBqld/9pzy22KmMGhj+MB1yfByZnA
wjk9oocrgBncj+s5AtyWy01BGZwmW72WotCdLHnWV+FIJ5ad7hFUFjHD08GnvqVx
ciIgYucmJXri1zIirhnetggSH66eDxeZqxWvxCja9rfOotpVCfdcBmugymgH
-----END CERTIFICATE-----

View File

@@ -0,0 +1 @@
0D8719B1C1968AE52BCA6B5FF0C7195751CFB8E9

View File

@@ -0,0 +1,89 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
53:71:d7:bb:71:c4:98:99:61:f8:2a:a9:69:ed:63:93:0d:64:e4:60
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=Mock CSCA
Validity
Not Before: Jan 5 12:12:10 2025 GMT
Not After : Jan 3 12:12:10 2035 GMT
Subject: CN=Mock CSCA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:d2:6e:38:41:f0:82:b8:ba:b1:98:c2:5a:05:f9:
83:2b:73:9d:5c:a3:77:78:d2:62:07:f7:dc:26:44:
ed:32:29:eb:6d:e5:c9:82:cd:06:5f:24:b6:1c:91:
77:2c:4c:39:b3:dc:90:42:54:3e:55:ae:81:e7:e4:
ce:5a:83:dd:4f:fa:4e:4c:99:1d:ea:2f:3f:eb:5a:
64:a9:66:65:d8:23:e6:02:09:66:9f:9d:24:01:be:
0c:16:42:65:cf:4f:c9:26:0f:5a:14:fc:3c:14:12:
13:29:ff:af:d8:65:5d:dc:56:55:dd:39:3b:00:3c:
c9:78:e6:9a:06:c7:c4:68:08:36:43:f5:c5:c1:ab:
c3:0e:b7:c0:3a:14:0b:d2:0c:eb:26:e8:92:53:0c:
b0:3e:dd:63:e9:1d:e2:99:8e:81:6b:66:ec:b3:46:
f2:8d:d7:5a:1d:d5:5a:2a:05:c9:2f:6a:49:9c:a5:
e8:c2:b0:7f:43:c9:83:37:63:5c:1a:04:2b:19:50:
d4:fa:45:0f:cf:74:6a:ed:89:14:83:45:44:ce:0d:
4f:92:a8:16:d6:91:8c:9d:8a:4b:32:45:10:5c:12:
a5:59:bb:15:b9:d9:84:1c:a3:f7:10:d7:ac:b1:9c:
eb:07:f8:db:37:c4:a4:36:fe:5b:64:83:4a:c7:b6:
33:09:1e:b5:db:d1:57:d6:ba:55:43:b9:3c:78:1b:
77:d8:11:be:f2:1d:a0:ab:79:98:b7:8c:df:dc:67:
b5:8a:2d:92:b6:71:eb:ca:30:bf:5d:70:bf:e7:49:
61:35:f1:c4:12:54:fd:e8:f6:a8:62:17:73:74:63:
39:02:8f:3e:34:9c:62:05:18:2f:13:ab:93:42:31:
aa:90:88:38:a9:db:07:2e:dd:86:e0:52:e9:57:e8:
9e:49:b4:9b:49:33:6f:47:77:98:fa:52:43:76:e0:
a7:05:ba:89:86:3a:22:4e:d0:1f:c3:56:d2:60:bd:
3a:0f:e8:2f:4b:54:02:a8:13:06:8f:c7:41:a8:6b:
e8:23:c2:b4:38:96:14:9a:42:56:04:0e:8c:8c:b2:
96:b5:1a:08:d1:b8:ce:c8:e3:56:59:68:c3:1d:d7:
07:66:56:1a:00:dd:e7:7e:00:cd:0c:4b:09:32:7b:
c6:fe:25:56:4e:93:a9:19:df:6a:f6:d9:1f:05:a6:
1b:65:54:c4:50:c5:98:d0:c1:3a:ae:dc:9c:ce:bd:
dc:fb:e8:b1:e9:32:2d:ea:16:d3:15:da:a6:a9:68:
0e:54:16:71:1e:39:cd:81:cc:37:1c:c0:e0:9f:01:
82:62:9e:09:f0:11:aa:56:eb:b0:e5:e4:d4:dd:1a:
b2:df:b7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
D8:69:81:B4:FD:E9:45:1F:D9:FD:A6:C4:31:9C:84:5C:3C:B2:A5:6A
X509v3 Authority Key Identifier:
D8:69:81:B4:FD:E9:45:1F:D9:FD:A6:C4:31:9C:84:5C:3C:B2:A5:6A
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
56:68:81:05:ae:8c:45:59:6b:5d:14:0f:13:35:47:c2:41:c6:
0b:73:90:50:e7:d9:2a:a4:c5:9b:fd:86:dd:54:c7:80:47:e0:
45:29:16:07:91:26:83:af:57:df:a3:e2:83:06:64:57:cf:91:
aa:2c:cd:bc:97:86:7c:07:47:09:70:21:b0:4e:5c:78:d2:ec:
62:4d:40:8e:72:32:30:fe:04:0a:40:7f:9e:9b:5b:f8:d9:f9:
29:3b:c4:40:13:43:22:c3:96:51:3d:7b:d6:17:02:c4:d0:f0:
eb:16:49:d2:68:9b:82:9a:ef:1d:d3:54:a1:f3:aa:dc:92:ce:
56:3c:48:96:84:9a:76:99:dd:36:66:18:d1:fc:6b:3c:ed:f6:
29:a5:66:e4:5b:25:07:40:23:6f:11:40:28:40:30:b4:0c:f3:
43:57:1c:94:e7:79:5e:4c:69:ea:3e:7d:08:f2:07:85:2f:85:
a4:43:80:da:de:21:aa:cf:2e:eb:9a:56:c2:a7:3c:f7:0f:3a:
26:5f:ce:a7:80:78:91:1a:10:6c:18:39:1a:d8:5a:b4:04:46:
a3:6f:72:f3:96:ed:b0:21:fc:9a:0e:7d:24:cf:76:0b:71:de:
55:dc:52:18:2e:96:ab:1e:4d:d7:5d:6d:e0:a4:be:61:e0:6c:
21:23:ce:1e:d2:a8:50:d1:75:4b:8b:de:03:6c:e1:f0:04:f4:
ae:f3:f6:c0:39:83:b1:76:ab:d9:20:60:33:b4:6f:f2:af:28:
28:7d:79:69:67:a2:d1:07:77:ae:d5:31:ea:02:0c:5d:7c:de:
fc:b4:00:b7:98:c5:d1:9a:9a:dd:f0:ba:09:4b:51:7e:6f:2e:
1c:19:ef:42:33:1d:31:e7:43:d7:2d:41:34:3a:76:88:5c:83:
02:b8:c2:bd:0d:8e:11:23:0b:b3:80:1c:c4:5f:78:5e:45:40:
7d:35:0d:fb:34:17:b7:38:80:9e:8d:1e:32:e6:4e:67:1e:79:
a6:ef:cb:f2:c9:06:50:ca:ac:35:20:df:89:04:6d:9f:5b:fa:
82:68:06:a9:5d:ff:da:73:cb:6d:8a:98:c1:a1:8f:e3:01:d7:
27:c1:c9:99:c0:c2:39:3d:a2:87:2b:80:19:dc:8f:eb:39:02:
dc:96:cb:4d:41:19:9c:26:5b:bd:96:a2:d0:9d:2c:79:d6:57:
e1:48:27:96:9d:ee:11:54:16:31:c3:d3:c1:a7:be:a5:71:72:
22:20:62:e7:26:25:7a:e2:d7:32:22:ae:19:de:b6:08:12:1f:
ae:9e:0f:17:99:ab:15:af:c4:28:da:f6:b7:ce:a2:da:55:09:
f7:5c:06:6b:a0:ca:68:07

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDSbjhB8IK4urGY
wloF+YMrc51co3d40mIH99wmRO0yKett5cmCzQZfJLYckXcsTDmz3JBCVD5VroHn
5M5ag91P+k5MmR3qLz/rWmSpZmXYI+YCCWafnSQBvgwWQmXPT8kmD1oU/DwUEhMp
/6/YZV3cVlXdOTsAPMl45poGx8RoCDZD9cXBq8MOt8A6FAvSDOsm6JJTDLA+3WPp
HeKZjoFrZuyzRvKN11od1VoqBckvakmcpejCsH9DyYM3Y1waBCsZUNT6RQ/PdGrt
iRSDRUTODU+SqBbWkYydiksyRRBcEqVZuxW52YQco/cQ16yxnOsH+Ns3xKQ2/ltk
g0rHtjMJHrXb0VfWulVDuTx4G3fYEb7yHaCreZi3jN/cZ7WKLZK2cevKML9dcL/n
SWE18cQSVP3o9qhiF3N0YzkCjz40nGIFGC8Tq5NCMaqQiDip2wcu3YbgUulX6J5J
tJtJM29Hd5j6UkN24KcFuomGOiJO0B/DVtJgvToP6C9LVAKoEwaPx0Goa+gjwrQ4
lhSaQlYEDoyMspa1GgjRuM7I41ZZaMMd1wdmVhoA3ed+AM0MSwkye8b+JVZOk6kZ
32r22R8FphtlVMRQxZjQwTqu3JzOvdz76LHpMi3qFtMV2qapaA5UFnEeOc2BzDcc
wOCfAYJingnwEapW67Dl5NTdGrLftwIDAQABAoICABf5DY4EN+g9VfaODFJ07VVv
FkTTrKHbmeZy0tDwoPMfj8jVLlf+l9S7/8aREzoSia+swinZo2urIJ/fUwZAfTSG
KBMVjdu8O/R0jQDi1QRte9/MhrVKt4DpT+2Il++pFRncaDSkKGCtpHhFlENmB5jj
+bk6XWHhYEnWlO05J0N7eASAWeH+pDn82LiPyGmgJiP9x+RlOX5Cm4YXF6sgbyxi
Aoz0BAsBDIJXPYPfD99Hz7tkXU2HbPWMiKyFNHIUT9Knq55tbWfYHpxmtasKIlS1
HdUaiCuJU7MuP53U/Lr4jCovpEHS1CMCfPxIDc5YOaBkC0QMXMbqbaqtmGstyHId
sAxPI6ybvV6gaR8fRwVqtDvzt5u9qCi2UcVJiWluqwW9rM2A5fgQohME3HfH1gAd
e8lSypehkU44K0zR25DpsBi18hVRObGw/UaRIm44EzyFyYvCdzEVtvqzP9WV5nlg
6ip1d1EgcbGjd692dZ4VyfN1A9M7yoxTer0cL2CwaMSs23FKmbacyLYv80RM8qtX
4s6zVPN+nzeiwhI9WZ3f0mqMvs9Bh8oAT6p4Wj1Xswp3aqjTOR+kWLKXYtiHgZx8
bDyMy8lAFfDUSfD0Ca0gYDOv3Mi6i1H+WYeWHivs46A6eyzR+f8xRnAaLwgb/Nik
0iDcBtoSNCjBR+bXRpRhAoIBAQD4/htSRvdPZTRtzFTqQB7I66IqcuGRveLepbmY
SZHXIAmarS+VQ0n+hCASKZyw23zu8J8986F3J/Sr8KyESnpv22OPmBTxj4v/pw57
3hSpeflXKNYTyL2+f9o1cTHWGe6z04CNN1PbCkREze2C9j++TxapOxR4ZBYrMzfw
hhL4OvRWXmNoWxu0/yXTRMabbfaYkPE1aRPfPvGFEHbEe61vL7s1kFFFAxoSrovv
riT/g+dCDk+W6ZE0d87uUel0w5FcRj4w3tKmMIvLnQA+3MmDrcpW7Fp3PKzhTN6Q
AF+Pae9i3p8WjboOQ4ZHz+LWdDA9s19oUfdL3cZFTK8VIvmXAoIBAQDYWknktpne
EPJPy6ghXbDqi53O5+HxpEnsZzz6hUr2nVC/c/BDardPkzIq/P1ndKy1lhkZM31D
ChcjbSClLX+9Czhx8C+vXiBWy2Bouc+zPHC46Ua8Z+5T4SYMuKY6nV7duF1lx7e1
acFSqvyEaWMc2slpoNJL9rvUjLvZJXjr6G9O2OAOm87ZjMNTxwMJTvDfy9L2UvJj
CRI5NI039rHM3ZmxFRwnGFikzAgP35nkVEYA9AsTPEROwFDdcoBOwbZ5esg1ABfF
ixYHRsPeqg2mH4iFiClnVFAhVtrhXu2L68Vw/+qepAy7SLTNXRKtGZfRQCs4h8jn
W9ZCo+6Gks7hAoIBAQDcJghQGfDmIQxXHDfkGidd7IEoWQS6EJM72nmbfUjWVTxI
p2GP7rvIrleQ13v0H0x6EwQpCXU03n4FXDmciiFxLx/7QTMbVZkpxDIZMQVBx1e/
SZrmSTIC8hYj9F5k9+7GznU15rpcy9oKn6ylg0Ze5JybqmHyBERZk+Kc5l51XeLV
ToVEKnH3+TQfdQrJOFO1F0o9uBda5tMynJj2Jof069XxiRViGFkANZYCqA2MYbqh
+/dA7mh1ZIzwyDnLBHNMi8rG+Ox1Bi1ELR+fdSUzKQDjE/z0ug/88DNETSAwtDB1
UXKFxW/A1tEuQ09D390bYLI1kWs+h+qbMS8IWDEnAoIBAClbmSSPg3pf4vI+DDXU
oy0y40faK+b1cOwwEAgT0vCxwe3XS+aXT9N2X/C3y/kq5JkRyFp47UkTdLjg84yf
1ftdWbzuHS943tW4qwVZ/8pTk3jFnzAE7ho6v/tOkPhDfQ8FX1VFiGi1fq8+4Gav
frLVYAtBIvJCiEVpYb9w2ly+YgjAjJQ+VJxhvDUXpgzxejpNzFYqJQupgEJPOW+p
SPPQqMChOHCAxvE5z5C5PcHYGkm0XSmgK66iNNMgQEbN4QP35K29Bs5MeDmL3YWD
HHjVLlPYY5HNHERDRjQu4VoOCABB66fH1Gc4ztczI47ThaIKkjiMPGt9sseqbr5q
8gECggEAdwbfVu9UmvLttfDFRZTQYjEmG9xEQtFK+fMEdIHMp3clhRsvbHeeyUqA
s5RD2/la2/yzJnnxozZve5hVNZcK4m8Rx7Xe8qcHmV7PXiiEBJi+5ZVQ+Vub3RO/
/F7HJYHYf1KtZH8S6eXBRq4dhOWpjhCqnNJjYnPJEB/F0YjDNvrnV8maomiHwxZN
oUrSdPDltWMbNWxJXyL9YQNB6u8HBcPeYI/oxA3Ey/Mj/zot71jaJIGIpnzE9yw/
2heZ3rIdlwyEu+A5u0xLaFMbkDn9kuWUTRm/wKXVK2iYkzChwOH7KWnoff5KKR3p
qsK/+x4W4uA/Zr6JxO5sMmqI2Ubyqg==
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,8 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBCjCBkgIBADATMREwDwYDVQQDDAhNb2NrIERTQzB2MBAGByqGSM49AgEGBSuB
BAAiA2IABJcHkktcOEim49CJ9XJgybYzwA76+dAO234h8RiXdoMG+fA1RCOiaWTw
fZNPZ+4WVZL69+qKfGoREW70CibyCElJugI91fAt+D8pGPxNOMzmst5cNYLDXOM8
UZ8/g+frOqAAMAoGCCqGSM49BAMCA2cAMGQCMFOGji5+Q5TfiHzCViOSpCtsgDvV
+ecUv6MGiFr1pfHVXbHgoAE2ixS+ed/LXX3ZpwIwHJ2qRDaWxMhFqMBgjrSIWbv7
vR/p/3jpKAQAmLuG5foVhsZN2Wi7Fk8pei4dS3ol
-----END CERTIFICATE REQUEST-----

View File

@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDUzCCATagAwIBAgIUDYcZscGWiuUrymtf8McZV1HPuOkwEgYJKoZIhvcNAQEK
MAWiAwIBIDAUMRIwEAYDVQQDDAlNb2NrIENTQ0EwHhcNMjUwMTA1MTIxMjEwWhcN
MjYwMTA1MTIxMjEwWjATMREwDwYDVQQDDAhNb2NrIERTQzB2MBAGByqGSM49AgEG
BSuBBAAiA2IABJcHkktcOEim49CJ9XJgybYzwA76+dAO234h8RiXdoMG+fA1RCOi
aWTwfZNPZ+4WVZL69+qKfGoREW70CibyCElJugI91fAt+D8pGPxNOMzmst5cNYLD
XOM8UZ8/g+frOqNCMEAwHQYDVR0OBBYEFNSFoVltdKnm+WoWGiEGCqIhCP15MB8G
A1UdIwQYMBaAFNhpgbT96UUf2f2mxDGchFw8sqVqMBIGCSqGSIb3DQEBCjAFogMC
ASADggIBAECM63yXNqLrOUooEdDnRWX0tno8+GJUZZa/BFm4ZfOTCtw3cH5aq5+5
XQAoPFz7G0bMyN3/3XvxZ2L4l+lMk2BjzIIiWvr3ssnlZfjIYwSuYdVy1XAcuriB
cmu8pN0VZGkp6IXwIciVNBj9SN9W7rsacqmqCx6e6WYMi85A8DslieSobpXrihFP
feip0HpFE1tcg4DYFXWKit4EuGQHuhax1payYsigXjeUseaun/PjqfXu1LVIrb/T
6CvcMZ7nttUBbr15nCchrkUWwD0O0l5xqI6iuMtlS3Sph/tMQo8obuVvgyBgF+PZ
YtK2FuNC8LRmu+lf6J3TVCArw5n6Xs4bVq9AFd+hq+zsC5+zRHVctQKTvYHDZWZT
ykPUBoBHoKoKIw9PibdBwXruVDgkYVN8uOi9gNtgxAT8i2gElRyZA5IGpA6Ov6yG
2hhMuXYz2y3yTCGic9n2kpgTKiEN/SFFkwKgNYFgxx68E/LQTRHET0U8jd81MMk5
jfkd2q0rMmuUnR9UJaML6KR+uDimmJ5sFgB554bi4celuHweK5Jma1AaSGgywhqm
iseo6+Z0RI3/Qg6Iq99YaUZdJv7Ei/xUwyO/ALM/DnZdApgFO+cpEODdt5U3sukA
/OEle+F0PODMfa2140mDEo0r5Jn+AZjR5VswzDv25EwsyyhrPkMe
-----END CERTIFICATE-----

View File

@@ -0,0 +1,68 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
0d:87:19:b1:c1:96:8a:e5:2b:ca:6b:5f:f0:c7:19:57:51:cf:b8:e9
Signature Algorithm: rsassaPss
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0x20
Trailer Field: 0x01 (default)
Issuer: CN=Mock CSCA
Validity
Not Before: Jan 5 12:12:10 2025 GMT
Not After : Jan 5 12:12:10 2026 GMT
Subject: CN=Mock DSC
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:97:07:92:4b:5c:38:48:a6:e3:d0:89:f5:72:60:
c9:b6:33:c0:0e:fa:f9:d0:0e:db:7e:21:f1:18:97:
76:83:06:f9:f0:35:44:23:a2:69:64:f0:7d:93:4f:
67:ee:16:55:92:fa:f7:ea:8a:7c:6a:11:11:6e:f4:
0a:26:f2:08:49:49:ba:02:3d:d5:f0:2d:f8:3f:29:
18:fc:4d:38:cc:e6:b2:de:5c:35:82:c3:5c:e3:3c:
51:9f:3f:83:e7:eb:3a
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
X509v3 Subject Key Identifier:
D4:85:A1:59:6D:74:A9:E6:F9:6A:16:1A:21:06:0A:A2:21:08:FD:79
X509v3 Authority Key Identifier:
D8:69:81:B4:FD:E9:45:1F:D9:FD:A6:C4:31:9C:84:5C:3C:B2:A5:6A
Signature Algorithm: rsassaPss
Signature Value:
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0x20
Trailer Field: 0x01 (default)
40:8c:eb:7c:97:36:a2:eb:39:4a:28:11:d0:e7:45:65:f4:b6:
7a:3c:f8:62:54:65:96:bf:04:59:b8:65:f3:93:0a:dc:37:70:
7e:5a:ab:9f:b9:5d:00:28:3c:5c:fb:1b:46:cc:c8:dd:ff:dd:
7b:f1:67:62:f8:97:e9:4c:93:60:63:cc:82:22:5a:fa:f7:b2:
c9:e5:65:f8:c8:63:04:ae:61:d5:72:d5:70:1c:ba:b8:81:72:
6b:bc:a4:dd:15:64:69:29:e8:85:f0:21:c8:95:34:18:fd:48:
df:56:ee:bb:1a:72:a9:aa:0b:1e:9e:e9:66:0c:8b:ce:40:f0:
3b:25:89:e4:a8:6e:95:eb:8a:11:4f:7d:e8:a9:d0:7a:45:13:
5b:5c:83:80:d8:15:75:8a:8a:de:04:b8:64:07:ba:16:b1:d6:
96:b2:62:c8:a0:5e:37:94:b1:e6:ae:9f:f3:e3:a9:f5:ee:d4:
b5:48:ad:bf:d3:e8:2b:dc:31:9e:e7:b6:d5:01:6e:bd:79:9c:
27:21:ae:45:16:c0:3d:0e:d2:5e:71:a8:8e:a2:b8:cb:65:4b:
74:a9:87:fb:4c:42:8f:28:6e:e5:6f:83:20:60:17:e3:d9:62:
d2:b6:16:e3:42:f0:b4:66:bb:e9:5f:e8:9d:d3:54:20:2b:c3:
99:fa:5e:ce:1b:56:af:40:15:df:a1:ab:ec:ec:0b:9f:b3:44:
75:5c:b5:02:93:bd:81:c3:65:66:53:ca:43:d4:06:80:47:a0:
aa:0a:23:0f:4f:89:b7:41:c1:7a:ee:54:38:24:61:53:7c:b8:
e8:bd:80:db:60:c4:04:fc:8b:68:04:95:1c:99:03:92:06:a4:
0e:8e:bf:ac:86:da:18:4c:b9:76:33:db:2d:f2:4c:21:a2:73:
d9:f6:92:98:13:2a:21:0d:fd:21:45:93:02:a0:35:81:60:c7:
1e:bc:13:f2:d0:4d:11:c4:4f:45:3c:8d:df:35:30:c9:39:8d:
f9:1d:da:ad:2b:32:6b:94:9d:1f:54:25:a3:0b:e8:a4:7e:b8:
38:a6:98:9e:6c:16:00:79:e7:86:e2:e1:c7:a5:b8:7c:1e:2b:
92:66:6b:50:1a:48:68:32:c2:1a:a6:8a:c7:a8:eb:e6:74:44:
8d:ff:42:0e:88:ab:df:58:69:46:5d:26:fe:c4:8b:fc:54:c3:
23:bf:00:b3:3f:0e:76:5d:02:98:05:3b:e7:29:10:e0:dd:b7:
95:37:b2:e9:00:fc:e1:25:7b:e1:74:3c:e0:cc:7d:ad:b5:e3:
49:83:12:8d:2b:e4:99:fe:01:98:d1:e5:5b:30:cc:3b:f6:e4:
4c:2c:cb:28:6b:3e:43:1e

View File

@@ -0,0 +1,6 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDDabeMgcheTsizT6aH0CiXxb1gvSHQNjbcqJCooAljzzEyLdAeCOhoA
ureFOIfii2ugBwYFK4EEACKhZANiAASXB5JLXDhIpuPQifVyYMm2M8AO+vnQDtt+
IfEYl3aDBvnwNUQjomlk8H2TT2fuFlWS+vfqinxqERFu9Aom8ghJSboCPdXwLfg/
KRj8TTjM5rLeXDWCw1zjPFGfP4Pn6zo=
-----END EC PRIVATE KEY-----

View File

@@ -1,129 +1,141 @@
export interface StandardCurve {
name: string;
p: string;
a: string;
b: string;
G: string;
n: string;
h: string;
name: string;
p: string;
a: string;
b: string;
G: string;
n: string;
h: string;
}
export const standardCurves: StandardCurve[] = [
{
name: "secp256r1",
p: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
a: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
b: "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
G: "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
n: "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
h: "01"
},
{
name: "secp384r1",
p: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
a: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
b: "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
G: "04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
n: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
h: "01"
},
{
name: "secp521r1",
p: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
a: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
b: "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
G: "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
n: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
h: "01"
}
,
{
name: "brainpoolP224r1",
p: "d7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff",
a: "68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43",
b: "2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b",
G: "040d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd",
n: "d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f",
h: "01"
},
{
name: "brainpoolP256r1",
p: "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377",
a: "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9",
b: "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6",
G: "048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997",
n: "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7",
h: "01"
},
{
name: "brainpoolP384r1",
p: "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53",
a: "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826",
b: "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11",
G: "041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315",
n: "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565",
h: "01"
},
{
name: "brainpoolP512r1",
p: "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3",
a: "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA",
b: "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723",
G: "0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892",
n: "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069",
h: "01"
}
{
name: 'secp256r1',
p: 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF',
a: 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC',
b: '5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B',
G: '046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5',
n: 'FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551',
h: '01',
},
{
name: 'secp384r1',
p: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF',
a: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC',
b: 'B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF',
G: '04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F',
n: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973',
h: '01',
},
{
name: 'secp521r1',
p: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
a: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC',
b: '0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00',
G: '0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650',
n: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409',
h: '01',
},
{
name: 'brainpoolP224r1',
p: 'd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff',
a: '68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43',
b: '2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b',
G: '040d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd',
n: 'd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f',
h: '01',
},
{
name: 'brainpoolP256r1',
p: 'A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377',
a: '7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9',
b: '26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6',
G: '048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997',
n: 'A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7',
h: '01',
},
{
name: 'brainpoolP384r1',
p: '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53',
a: '7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826',
b: '04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11',
G: '041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315',
n: '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565',
h: '01',
},
{
name: 'brainpoolP512r1',
p: 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3',
a: '7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA',
b: '3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723',
G: '0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892',
n: 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069',
h: '01',
},
];
export function normalizeHex(hex: string): string {
return hex.toLowerCase().replace(/^0x/, '').replace(/^00/, '');
return hex.toLowerCase().replace(/^0x/, '').replace(/^00/, '');
}
export function identifyCurve(params: any): string {
const normalizedParams = {
p: normalizeHex(params.p),
a: normalizeHex(params.a),
b: normalizeHex(params.b),
G: normalizeHex(params.G),
n: normalizeHex(params.n),
h: normalizeHex(params.h)
};
const normalizedParams = {
p: normalizeHex(params.p),
a: normalizeHex(params.a),
b: normalizeHex(params.b),
G: normalizeHex(params.G),
n: normalizeHex(params.n),
h: normalizeHex(params.h),
};
for (const curve of standardCurves) {
if (
normalizedParams.p === normalizeHex(curve.p) &&
normalizedParams.a === normalizeHex(curve.a) &&
normalizedParams.b === normalizeHex(curve.b) &&
normalizedParams.G === normalizeHex(curve.G) &&
normalizedParams.n === normalizeHex(curve.n) &&
normalizedParams.h === normalizeHex(curve.h)
) {
return curve.name;
}
for (const curve of standardCurves) {
if (
normalizedParams.p === normalizeHex(curve.p) &&
normalizedParams.a === normalizeHex(curve.a) &&
normalizedParams.b === normalizeHex(curve.b) &&
normalizedParams.G === normalizeHex(curve.G) &&
normalizedParams.n === normalizeHex(curve.n) &&
normalizedParams.h === normalizeHex(curve.h)
) {
return curve.name;
}
console.log("Unknown curve:", normalizedParams);
return "Unknown curve";
}
console.log('Unknown curve:', normalizedParams);
return 'Unknown curve';
}
export function getECDSACurveBits(curveName: string): string {
const curveBits: { [key: string]: number } = {
'secp256r1': 256,
'secp384r1': 384,
'secp521r1': 521,
'brainpoolP224r1': 224,
'brainpoolP256r1': 256,
'brainpoolP384r1': 384,
'brainpoolP512r1': 512,
'secp256r1 (NIST P-256)': 256,
'secp384r1 (NIST P-384)': 384,
'secp521r1 (NIST P-521)': 521,
const curveBits: { [key: string]: number } = {
secp224r1: 224,
secp256r1: 256,
secp384r1: 384,
secp521r1: 521,
brainpoolP224r1: 224,
brainpoolP256r1: 256,
brainpoolP384r1: 384,
brainpoolP512r1: 512,
};
if (curveName in curveBits) {
return curveBits[curveName].toString();
}
console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`);
return 'unknown';
}
export function getCurveForElliptic(curveName: string): string {
const curves = {
secp224r1: 'p224',
secp256r1: 'p256',
secp384r1: 'p384',
secp521r1: 'p521',
brainpoolP224r1: 'brainpoolP224r1',
brainpoolP256r1: 'brainpoolP256r1',
brainpoolP384r1: 'brainpoolP384r1',
brainpoolP512r1: 'brainpoolP512r1',
};
};
if (curveName in curveBits) {
return curveBits[curveName].toString();
}
console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`);
return "unknown";
if (!curves[curveName]) {
throw new Error('Invalid curve: ' + curveName);
}
}
return curves[curveName];
}

View File

@@ -1,35 +1,41 @@
import { StandardCurve } from "./curves";
import { StandardCurve } from './curves';
export interface CertificateData {
id: string;
issuer: string;
validity: {
notBefore: string;
notAfter: string;
};
subjectKeyIdentifier: string;
authorityKeyIdentifier: string;
signatureAlgorithm: string;
hashAlgorithm: string;
publicKeyDetails: PublicKeyDetailsRSA | PublicKeyDetailsECDSA | PublicKeyDetailsRSAPSS | undefined;
rawPem: string;
rawTxt: string;
id: string;
issuer: string;
validity: {
notBefore: string;
notAfter: string;
};
subjectKeyIdentifier: string;
authorityKeyIdentifier: string;
signatureAlgorithm: string;
hashAlgorithm: string;
publicKeyDetails:
| PublicKeyDetailsRSA
| PublicKeyDetailsECDSA
| PublicKeyDetailsRSAPSS
| undefined;
rawPem: string;
rawTxt: string;
}
export interface PublicKeyDetailsRSA {
modulus: string;
exponent: string;
bits: string;
modulus: string;
exponent: string;
bits: string;
}
export interface PublicKeyDetailsRSAPSS extends PublicKeyDetailsRSA {
hashAlgorithm: string;
mgf: string;
saltLength: string;
hashAlgorithm: string;
mgf: string;
saltLength: string;
}
export interface PublicKeyDetailsECDSA {
curve: string;
params: StandardCurve;
bits: string;
}
x: string;
y: string;
curve: string;
params: StandardCurve;
bits: string;
}

View File

@@ -1,127 +1,138 @@
export const oidMap: { [key: string]: string } = {
"1.2.840.113549.3.7": "3des",
"2.16.840.1.101.3.4.1.2": "aes128",
"2.16.840.1.101.3.4.1.5": "aes128wrap",
"2.16.840.1.101.3.4.1.22": "aes192",
"2.16.840.1.101.3.4.1.25": "aes192wrap",
"2.16.840.1.101.3.4.1.42": "aes256",
"2.16.840.1.101.3.4.1.45": "aes256wrap",
"1.3.36.3.3.2.8.1.1.1": "brainpoolP160r1",
"1.3.36.3.3.2.8.1.1.2": "brainpoolP160t1",
"1.3.36.3.3.2.8.1.1.3": "brainpoolP192r1",
"1.3.36.3.3.2.8.1.1.4": "brainpoolP192t1",
"1.3.36.3.3.2.8.1.1.5": "brainpoolP224r1",
"1.3.36.3.3.2.8.1.1.6": "brainpoolP224t1",
"1.3.36.3.3.2.8.1.1.7": "brainpoolP256r1",
"1.3.36.3.3.2.8.1.1.8": "brainpoolP256t1",
"1.3.36.3.3.2.8.1.1.9": "brainpoolP320r1",
"1.3.36.3.3.2.8.1.1.10": "brainpoolP320t1",
"1.3.36.3.3.2.8.1.1.11": "brainpoolP384r1",
"1.3.36.3.3.2.8.1.1.12": "brainpoolP384t1",
"1.3.36.3.3.2.8.1.1.13": "brainpoolP512r1",
"1.3.36.3.3.2.8.1.1.14": "brainpoolP512t1",
"2.5.4.6": "C",
"1.2.840.113549.1.9.16.3.6": "CMS3DESwrap",
"1.2.840.113549.1.9.16.3.7": "CMSRC2wrap",
"2.5.4.3": "CN",
"1.3.6.1.5.5.7.2.1": "CPS",
"0.9.2342.19200300.100.1.25": "DC",
"1.3.14.3.2.7": "des",
"2.5.4.13": "Description",
"1.2.840.10046.2.1": "DH",
"2.5.4.46": "dnQualifier",
"1.2.840.10040.4.1": "DSA",
"1.3.14.3.2.27": "dsaSHA1",
"1.2.840.113549.1.9.1": "E",
"1.2.156.11235.1.1.2.1": "ec192wapi",
"1.2.840.10045.2.1": "ECC",
"1.3.133.16.840.63.0.2": "ECDH_STD_SHA1_KDF",
"1.3.132.1.11.1": "ECDH_STD_SHA256_KDF",
"1.3.132.1.11.2": "ECDH_STD_SHA384_KDF",
"1.2.840.10045.3.1.7": "ECDSA_P256",
"1.3.132.0.34": "ECDSA_P384",
"1.3.132.0.35": "ECDSA_P521",
"1.2.840.113549.1.9.16.3.5": "ESDH",
"2.5.4.42": "G",
"2.5.4.43": "I",
"2.5.4.7": "L",
"1.2.840.113549.2.2": "md2",
"1.2.840.113549.1.1.2": "md2RSA",
"1.2.840.113549.2.4": "md4",
"1.2.840.113549.1.1.3": "md4RSA",
"1.2.840.113549.2.5": "md5",
"1.2.840.113549.1.1.4": "md5RSA",
"1.2.840.113549.1.1.8": "mgf1",
"2.16.840.1.101.2.1.1.20": "mosaicKMandUpdSig",
"2.16.840.1.101.2.1.1.19": "mosaicUpdatedSig",
"1.2.840.10045.3.1.1": "nistP192",
"1.3.132.0.33": "nistP224",
"1.3.6.1.5.5.7.6.2": "NO_SIGN",
"2.5.4.10": "O",
"2.5.4.11": "OU",
"2.5.4.20": "Phone",
"2.5.4.18": "POBox",
"2.5.4.17": "PostalCode",
"1.2.840.113549.3.2": "rc2",
"1.2.840.113549.3.4": "rc4",
"1.2.840.113549.1.1.1": "RSA",
"1.2.840.113549.1.1.7": "RSAES_OAEP",
"1.2.840.113549.1.1.10": "RSASSA_PSS",
"2.5.4.8": "S",
"1.3.132.0.9": "secP160k1",
"1.3.132.0.8": "secP160r1",
"1.3.132.0.30": "secP160r2",
"1.3.132.0.31": "secP192k1",
"1.3.132.0.32": "secP224k1",
"1.3.132.0.10": "secP256k1",
"2.5.4.5": "SERIALNUMBER",
"1.3.14.3.2.26": "sha1",
"1.2.840.10040.4.3": "sha1DSA",
"1.2.840.10045.4.1": "sha1ECDSA",
"1.2.840.113549.1.1.5": "sha1RSA",
"2.16.840.1.101.3.4.2.1": "sha256",
"1.2.840.10045.4.3.2": "sha256ECDSA",
"1.2.840.113549.1.1.11": "sha256RSA",
"2.16.840.1.101.3.4.2.2": "sha384",
"1.2.840.10045.4.3.3": "sha384ECDSA",
"1.2.840.113549.1.1.12": "sha384RSA",
"2.16.840.1.101.3.4.2.3": "sha512",
"1.2.840.10045.4.3.4": "sha512ECDSA",
"1.2.840.113549.1.1.13": "sha512RSA",
"2.5.4.4": "SN",
"1.2.840.10045.4.3": "specifiedECDSA",
"2.5.4.9": "STREET",
"2.5.4.12": "T",
"2.23.133.2.1": "TPMManufacturer",
"2.23.133.2.2": "TPMModel",
"2.23.133.2.3": "TPMVersion",
"2.23.43.1.4.9": "wtls9",
"2.5.4.24": "X21Address",
"1.2.840.10045.3.1.2": "x962P192v2",
"1.2.840.10045.3.1.3": "x962P192v3",
"1.2.840.10045.3.1.4": "x962P239v1",
"1.2.840.10045.3.1.5": "x962P239v2",
"1.2.840.10045.3.1.6": "x962P239v3",
'1.2.840.113549.3.7': '3des',
'2.16.840.1.101.3.4.1.2': 'aes128',
'2.16.840.1.101.3.4.1.5': 'aes128wrap',
'2.16.840.1.101.3.4.1.22': 'aes192',
'2.16.840.1.101.3.4.1.25': 'aes192wrap',
'2.16.840.1.101.3.4.1.42': 'aes256',
'2.16.840.1.101.3.4.1.45': 'aes256wrap',
'1.3.36.3.3.2.8.1.1.1': 'brainpoolP160r1',
'1.3.36.3.3.2.8.1.1.2': 'brainpoolP160t1',
'1.3.36.3.3.2.8.1.1.3': 'brainpoolP192r1',
'1.3.36.3.3.2.8.1.1.4': 'brainpoolP192t1',
'1.3.36.3.3.2.8.1.1.5': 'brainpoolP224r1',
'1.3.36.3.3.2.8.1.1.6': 'brainpoolP224t1',
'1.3.36.3.3.2.8.1.1.7': 'brainpoolP256r1',
'1.3.36.3.3.2.8.1.1.8': 'brainpoolP256t1',
'1.3.36.3.3.2.8.1.1.9': 'brainpoolP320r1',
'1.3.36.3.3.2.8.1.1.10': 'brainpoolP320t1',
'1.3.36.3.3.2.8.1.1.11': 'brainpoolP384r1',
'1.3.36.3.3.2.8.1.1.12': 'brainpoolP384t1',
'1.3.36.3.3.2.8.1.1.13': 'brainpoolP512r1',
'1.3.36.3.3.2.8.1.1.14': 'brainpoolP512t1',
'2.5.4.6': 'C',
'1.2.840.113549.1.9.16.3.6': 'CMS3DESwrap',
'1.2.840.113549.1.9.16.3.7': 'CMSRC2wrap',
'2.5.4.3': 'CN',
'1.3.6.1.5.5.7.2.1': 'CPS',
'0.9.2342.19200300.100.1.25': 'DC',
'1.3.14.3.2.7': 'des',
'2.5.4.13': 'Description',
'1.2.840.10046.2.1': 'DH',
'2.5.4.46': 'dnQualifier',
'1.2.840.10040.4.1': 'DSA',
'1.3.14.3.2.27': 'dsaSHA1',
'1.2.840.113549.1.9.1': 'E',
'1.2.156.11235.1.1.2.1': 'ec192wapi',
'1.2.840.10045.2.1': 'ECC',
'1.3.133.16.840.63.0.2': 'ECDH_STD_SHA1_KDF',
'1.3.132.1.11.1': 'ECDH_STD_SHA256_KDF',
'1.3.132.1.11.2': 'ECDH_STD_SHA384_KDF',
'1.2.840.10045.3.1.7': 'ECDSA_P256',
'1.3.132.0.34': 'ECDSA_P384',
'1.3.132.0.35': 'ECDSA_P521',
'1.2.840.113549.1.9.16.3.5': 'ESDH',
'2.5.4.42': 'G',
'2.5.4.43': 'I',
'2.5.4.7': 'L',
'1.2.840.113549.2.2': 'md2',
'1.2.840.113549.1.1.2': 'md2RSA',
'1.2.840.113549.2.4': 'md4',
'1.2.840.113549.1.1.3': 'md4RSA',
'1.2.840.113549.2.5': 'md5',
'1.2.840.113549.1.1.4': 'md5RSA',
'1.2.840.113549.1.1.8': 'mgf1',
'2.16.840.1.101.2.1.1.20': 'mosaicKMandUpdSig',
'2.16.840.1.101.2.1.1.19': 'mosaicUpdatedSig',
'1.2.840.10045.3.1.1': 'nistP192',
'1.3.132.0.33': 'nistP224',
'1.3.6.1.5.5.7.6.2': 'NO_SIGN',
'2.5.4.10': 'O',
'2.5.4.11': 'OU',
'2.5.4.20': 'Phone',
'2.5.4.18': 'POBox',
'2.5.4.17': 'PostalCode',
'1.2.840.113549.3.2': 'rc2',
'1.2.840.113549.3.4': 'rc4',
'1.2.840.113549.1.1.1': 'RSA',
'1.2.840.113549.1.1.7': 'RSAES_OAEP',
'1.2.840.113549.1.1.10': 'RSASSA_PSS',
'2.5.4.8': 'S',
'1.3.132.0.9': 'secP160k1',
'1.3.132.0.8': 'secP160r1',
'1.3.132.0.30': 'secP160r2',
'1.3.132.0.31': 'secP192k1',
'1.3.132.0.32': 'secP224k1',
'1.3.132.0.10': 'secP256k1',
'2.5.4.5': 'SERIALNUMBER',
'1.3.14.3.2.26': 'sha1',
'1.2.840.10040.4.3': 'sha1DSA',
'1.2.840.10045.4.1': 'sha1ECDSA',
'1.2.840.113549.1.1.5': 'sha1RSA',
'2.16.840.1.101.3.4.2.1': 'sha256',
'1.2.840.10045.4.3.2': 'sha256ECDSA',
'1.2.840.113549.1.1.11': 'sha256RSA',
'2.16.840.1.101.3.4.2.2': 'sha384',
'1.2.840.10045.4.3.3': 'sha384ECDSA',
'1.2.840.113549.1.1.12': 'sha384RSA',
'2.16.840.1.101.3.4.2.3': 'sha512',
'1.2.840.10045.4.3.4': 'sha512ECDSA',
'1.2.840.113549.1.1.13': 'sha512RSA',
'2.5.4.4': 'SN',
'1.2.840.10045.4.3': 'specifiedECDSA',
'2.5.4.9': 'STREET',
'2.5.4.12': 'T',
'2.23.133.2.1': 'TPMManufacturer',
'2.23.133.2.2': 'TPMModel',
'2.23.133.2.3': 'TPMVersion',
'2.23.43.1.4.9': 'wtls9',
'2.5.4.24': 'X21Address',
'1.2.840.10045.3.1.2': 'x962P192v2',
'1.2.840.10045.3.1.3': 'x962P192v3',
'1.2.840.10045.3.1.4': 'x962P239v1',
'1.2.840.10045.3.1.5': 'x962P239v2',
'1.2.840.10045.3.1.6': 'x962P239v3',
};
export const mapSecpCurves: { [key: string]: string } = {
ECDSA_224: 'secp224r1',
ECDSA_P256: 'secp256r1',
ECDSA_P384: 'secp384r1',
ECDSA_P521: 'secp521r1',
};
function getFriendlyNameSecpCurves(friendlyName: string): string {
return mapSecpCurves[friendlyName] || friendlyName;
}
export function getFriendlyName(oid: string): string {
return oidMap[oid] || "Unknown Algorithm";
return getFriendlyNameSecpCurves(oidMap[oid]) || 'Unknown Algorithm';
}
export function extractHashFunction(friendlyName: string): string {
if (friendlyName.toLowerCase().includes('sha1')) {
return 'sha1'
}
if (friendlyName.toLowerCase().includes('sha256')) {
return 'sha256'
}
if (friendlyName.toLowerCase().includes('sha384')) {
return 'sha384'
}
if (friendlyName.toLowerCase().includes('sha512')) {
return 'sha512'
}
throw new Error("hash function not found in: " + friendlyName);
if (friendlyName.toLowerCase().includes('sha1')) {
return 'sha1';
}
if (friendlyName.toLowerCase().includes('sha256')) {
return 'sha256';
}
if (friendlyName.toLowerCase().includes('sha384')) {
return 'sha384';
}
if (friendlyName.toLowerCase().includes('sha512')) {
return 'sha512';
}
throw new Error('hash function not found in: ' + friendlyName);
return 'unknown'
}
return 'unknown';
}

View File

@@ -1,275 +1,40 @@
import * as asn1js from "asn1js";
import { Certificate, RSAPublicKey, RSASSAPSSParams } from "pkijs";
import { extractHashFunction, getFriendlyName } from "./oids";
import { CertificateData, PublicKeyDetailsECDSA, PublicKeyDetailsRSA, PublicKeyDetailsRSAPSS } from "./dataStructure";
import { getECDSACurveBits, identifyCurve, StandardCurve } from "./curves";
import { getIssuerCountryCode, getSubjectKeyIdentifier } from "./utils";
import fs from 'fs';
import { execSync } from 'child_process';
import { getAuthorityKeyIdentifier } from "../certificates/handleCertificate";
import { parseCertificateSimple } from './parseCertificateSimple';
import { CertificateData } from './dataStructure';
export function parseCertificate(pem: string, fileName: string): any {
let certificateData: CertificateData = {
id: '',
issuer: '',
validity: {
notBefore: '',
notAfter: ''
},
subjectKeyIdentifier: '',
authorityKeyIdentifier: '',
signatureAlgorithm: '',
hashAlgorithm: '',
publicKeyDetails: undefined,
rawPem: '',
rawTxt: ''
};
let certificateData: CertificateData = {
id: '',
issuer: '',
validity: {
notBefore: '',
notAfter: '',
},
subjectKeyIdentifier: '',
authorityKeyIdentifier: '',
signatureAlgorithm: '',
hashAlgorithm: '',
publicKeyDetails: undefined,
rawPem: '',
rawTxt: '',
};
try {
certificateData = parseCertificateSimple(pem);
const tempCertPath = `/tmp/${fileName}.pem`;
fs.writeFileSync(tempCertPath, pem);
try {
certificateData = parseCertificateSimple(pem);
const tempCertPath = `/tmp/${fileName}.pem`;
fs.writeFileSync(tempCertPath, pem);
try {
const openSslOutput = execSync(`openssl x509 -in ${tempCertPath} -text -noout`).toString();
certificateData.rawTxt = openSslOutput;
} catch (error) {
console.error(`Error executing OpenSSL command: ${error}`);
certificateData.rawTxt = 'Error: Unable to generate human-readable format';
} finally {
fs.unlinkSync(tempCertPath);
}
return certificateData;
const openSslOutput = execSync(`openssl x509 -in ${tempCertPath} -text -noout`).toString();
certificateData.rawTxt = openSslOutput;
} catch (error) {
console.error(`Error processing certificate ${fileName}:`, error);
throw error;
}
}
export function parseCertificateSimple(pem: string): any {
let certificateData: CertificateData = {
id: '',
issuer: '',
validity: {
notBefore: '',
notAfter: ''
},
subjectKeyIdentifier: '',
authorityKeyIdentifier: '',
signatureAlgorithm: '',
hashAlgorithm: '',
publicKeyDetails: undefined,
rawPem: '',
rawTxt: ''
};
try {
const pemFormatted = pem.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n|\r)/g, "");
const binary = Buffer.from(pemFormatted, "base64");
const arrayBuffer = new ArrayBuffer(binary.length);
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < binary.length; i++) {
view[i] = binary[i];
}
const asn1 = asn1js.fromBER(arrayBuffer);
if (asn1.offset === -1) {
throw new Error(`ASN.1 parsing error: ${asn1.result.error}`);
}
const cert = new Certificate({ schema: asn1.result });
const publicKeyAlgoOID = cert.subjectPublicKeyInfo.algorithm.algorithmId;
const publicKeyAlgoFN = getFriendlyName(publicKeyAlgoOID);
const signatureAlgoOID = cert.signatureAlgorithm.algorithmId;
const signatureAlgoFN = getFriendlyName(signatureAlgoOID);
let params;
if (publicKeyAlgoFN === 'RSA') {
if (signatureAlgoFN === 'RSASSA_PSS') {
certificateData.signatureAlgorithm = "rsapss";
params = getParamsRSAPSS(cert);
certificateData.hashAlgorithm = (params as PublicKeyDetailsRSAPSS).hashAlgorithm;
}
else {
certificateData.hashAlgorithm = extractHashFunction(signatureAlgoFN);
certificateData.signatureAlgorithm = "rsa";
params = getParamsRSA(cert);
}
}
else if (publicKeyAlgoFN === 'ECC') {
certificateData.hashAlgorithm = extractHashFunction(signatureAlgoFN);
certificateData.signatureAlgorithm = "ecdsa";
params = getParamsECDSA(cert);
}
else if (publicKeyAlgoFN === 'RSASSA_PSS') {
certificateData.signatureAlgorithm = "rsapss";
//different certificate structure than the RSA/RSAPSS mix, we can't retrieve the modulus the same way as for RSA
// console.log(cert);
//TODO: implement the parsing of the RSASSA_PSS certificate
params = getParamsRSAPSS2(cert);
}
else {
console.log(publicKeyAlgoFN);
}
certificateData.publicKeyDetails = params;
certificateData.issuer = getIssuerCountryCode(cert);;
certificateData.validity = {
notBefore: cert.notBefore.value.toString(),
notAfter: cert.notAfter.value.toString()
};
const ski = getSubjectKeyIdentifier(cert);
certificateData.id = ski.slice(0, 12);
certificateData.subjectKeyIdentifier = ski;
certificateData.rawPem = pem;
const authorityKeyIdentifier = getAuthorityKeyIdentifier(cert);
certificateData.authorityKeyIdentifier = authorityKeyIdentifier;
return certificateData;
} catch (error) {
console.error(`Error processing certificate`, error);
throw error;
console.error(`Error executing OpenSSL command: ${error}`);
certificateData.rawTxt = 'Error: Unable to generate human-readable format';
} finally {
fs.unlinkSync(tempCertPath);
}
return certificateData;
} catch (error) {
console.error(`Error processing certificate ${fileName}:`, error);
throw error;
}
}
function getParamsRSA(cert: Certificate): PublicKeyDetailsRSA {
const publicKeyValue = cert.subjectPublicKeyInfo.parsedKey as RSAPublicKey;
const modulusBytes = publicKeyValue.modulus.valueBlock.valueHexView;
const modulusHex = Buffer.from(modulusBytes).toString('hex');
const exponentBigInt = publicKeyValue.publicExponent.toBigInt();
const exponentDecimal = exponentBigInt.toString();
const actualBits = modulusBytes.length * 8;
return {
modulus: modulusHex,
exponent: exponentDecimal,
bits: actualBits.toString()
};
}
function getParamsRSAPSS(cert: Certificate): PublicKeyDetailsRSAPSS {
const { modulus, exponent, bits } = getParamsRSA(cert);
const sigAlgParams = cert.signatureAlgorithm.algorithmParams;
const pssParams = new RSASSAPSSParams({ schema: sigAlgParams });
const hashAlgorithm = getFriendlyName(pssParams.hashAlgorithm.algorithmId);
const mgf = getFriendlyName(pssParams.maskGenAlgorithm.algorithmId);
return {
modulus: modulus,
exponent: exponent,
bits: bits,
hashAlgorithm: hashAlgorithm,
mgf: mgf,
saltLength: pssParams.saltLength.toString()
};
}
function getParamsRSAPSS2(cert: Certificate): PublicKeyDetailsRSAPSS {
// Get the subjectPublicKey BitString
const spki = cert.subjectPublicKeyInfo;
const spkiValueHex = spki.subjectPublicKey.valueBlock.valueHexView;
// Parse the public key ASN.1 structure
const asn1PublicKey = asn1js.fromBER(spkiValueHex);
if (asn1PublicKey.offset === -1) {
throw new Error("Error parsing public key ASN.1 structure");
}
// The public key is an RSAPublicKey structure
const rsaPublicKey = new RSAPublicKey({ schema: asn1PublicKey.result });
const modulusBytes = rsaPublicKey.modulus.valueBlock.valueHexView;
const modulusHex = Buffer.from(modulusBytes).toString('hex');
const exponentBigInt = rsaPublicKey.publicExponent.toBigInt();
const exponentDecimal = exponentBigInt.toString();
const actualBits = modulusBytes.length * 8;
const sigAlgParams = cert.signatureAlgorithm.algorithmParams;
const pssParams = new RSASSAPSSParams({ schema: sigAlgParams });
const hashAlgorithm = getFriendlyName(pssParams.hashAlgorithm.algorithmId);
const mgf = getFriendlyName(pssParams.maskGenAlgorithm.algorithmId);
return {
modulus: modulusHex,
exponent: exponentDecimal,
bits: actualBits.toString(),
hashAlgorithm: hashAlgorithm,
mgf: mgf,
saltLength: pssParams.saltLength.toString()
};
}
export function getParamsECDSA(cert: Certificate): PublicKeyDetailsECDSA {
try {
const algorithmParams = cert.subjectPublicKeyInfo.algorithm.algorithmParams;
if (!algorithmParams) {
console.log('No algorithm params found');
return { curve: 'Unknown', params: {} as StandardCurve, bits: 'Unknown' };
}
const params = asn1js.fromBER(algorithmParams.valueBeforeDecodeView).result;
const valueBlock: any = params.valueBlock;
if (valueBlock.value && valueBlock.value.length >= 5) {
const curveParams: StandardCurve = {} as StandardCurve;
// Field ID (index 1)
const fieldId = valueBlock.value[1];
if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) {
const fieldType = fieldId.valueBlock.value[0];
const prime = fieldId.valueBlock.value[1];
//curveParams.fieldType = fieldType.valueBlock.toString();
curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex');
}
// Curve Coefficients (index 2)
const curveCoefficients = valueBlock.value[2];
if (curveCoefficients && curveCoefficients.valueBlock && curveCoefficients.valueBlock.value) {
const a = curveCoefficients.valueBlock.value[0];
const b = curveCoefficients.valueBlock.value[1];
curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex');
curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex');
}
// Base Point G (index 3)
const basePoint = valueBlock.value[3];
if (basePoint && basePoint.valueBlock) {
curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex');
}
// Order n (index 4)
const order = valueBlock.value[4];
if (order && order.valueBlock) {
curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex');
}
if (valueBlock.value.length >= 6) {
// Cofactor h (index 5)
const cofactor = valueBlock.value[5];
if (cofactor && cofactor.valueBlock) {
curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex');
}
}
else {
curveParams.h = '01';
}
const identifiedCurve = identifyCurve(curveParams);
return { curve: identifiedCurve, params: curveParams, bits: getECDSACurveBits(identifiedCurve) };
} else {
if (valueBlock.value) {
console.log(valueBlock.value);
}
else {
console.log('No value block found');
}
}
} catch (error) {
console.error('Error parsing EC parameters:', error);
return { curve: 'Error', params: {} as StandardCurve, bits: 'Unknown' };
}
}

View File

@@ -0,0 +1,331 @@
import * as asn1js from 'asn1js';
import { Certificate, RSAPublicKey, RSASSAPSSParams } from 'pkijs';
import { getFriendlyName } from './oids';
import {
CertificateData,
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
} from './dataStructure';
import { getCurveForElliptic, getECDSACurveBits, identifyCurve, StandardCurve } from './curves';
import { getIssuerCountryCode, getSubjectKeyIdentifier } from './utils';
import { circuitNameFromMode } from '../../constants/constants';
import { Mode } from '../appType';
import { initElliptic } from '../elliptic';
export function parseCertificateSimple(pem: string): CertificateData {
let certificateData: CertificateData = {
id: '',
issuer: '',
validity: {
notBefore: '',
notAfter: '',
},
subjectKeyIdentifier: '',
authorityKeyIdentifier: '',
signatureAlgorithm: '',
hashAlgorithm: '',
publicKeyDetails: undefined,
rawPem: '',
rawTxt: '',
};
try {
const pemFormatted = pem.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n|\r)/g, '');
const binary = Buffer.from(pemFormatted, 'base64');
const arrayBuffer = new ArrayBuffer(binary.length);
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < binary.length; i++) {
view[i] = binary[i];
}
const asn1 = asn1js.fromBER(arrayBuffer);
if (asn1.offset === -1) {
throw new Error(`ASN.1 parsing error: ${asn1.result.error}`);
}
const cert = new Certificate({ schema: asn1.result });
const publicKeyAlgoOID = cert.subjectPublicKeyInfo.algorithm.algorithmId;
const publicKeyAlgoFN = getFriendlyName(publicKeyAlgoOID);
const signatureAlgoOID = cert.signatureAlgorithm.algorithmId;
const signatureAlgoFN = getFriendlyName(signatureAlgoOID);
certificateData.hashAlgorithm = getHashAlgorithm(signatureAlgoFN);
let params;
if (publicKeyAlgoFN === 'RSA') {
certificateData.signatureAlgorithm = 'rsa';
params = getParamsRSA(cert);
} else if (publicKeyAlgoFN === 'ECC') {
certificateData.signatureAlgorithm = 'ecdsa';
params = getParamsECDSA(cert);
} else if (publicKeyAlgoFN === 'RSASSA_PSS') {
certificateData.signatureAlgorithm = 'rsapss';
params = getParamsRSAPSS(cert);
} else {
console.log(publicKeyAlgoFN);
}
certificateData.publicKeyDetails = params;
certificateData.issuer = getIssuerCountryCode(cert);
certificateData.validity = {
notBefore: cert.notBefore.value.toString(),
notAfter: cert.notAfter.value.toString(),
};
const ski = getSubjectKeyIdentifier(cert);
certificateData.id = ski.slice(0, 12);
certificateData.subjectKeyIdentifier = ski;
certificateData.rawPem = pem;
const authorityKeyIdentifier = getAuthorityKeyIdentifier(cert);
certificateData.authorityKeyIdentifier = authorityKeyIdentifier;
// corner case for rsapss
if (certificateData.signatureAlgorithm === 'rsapss' && !certificateData.hashAlgorithm) {
certificateData.hashAlgorithm = (
certificateData.publicKeyDetails as PublicKeyDetailsRSAPSS
).hashAlgorithm;
}
return certificateData;
} catch (error) {
console.error(`Error processing certificate`, error);
throw error;
}
}
function getParamsRSA(cert: Certificate): PublicKeyDetailsRSA {
const publicKeyValue = cert.subjectPublicKeyInfo.parsedKey as RSAPublicKey;
const modulusBytes = publicKeyValue.modulus.valueBlock.valueHexView;
const modulusHex = Buffer.from(modulusBytes).toString('hex');
const exponentBigInt = publicKeyValue.publicExponent.toBigInt();
const exponentDecimal = exponentBigInt.toString();
const actualBits = modulusBytes.length * 8;
return {
modulus: modulusHex,
exponent: exponentDecimal,
bits: actualBits.toString(),
};
}
function getParamsRSAPSS(cert: Certificate): PublicKeyDetailsRSAPSS {
// Get the subjectPublicKey BitString
const spki = cert.subjectPublicKeyInfo;
const spkiValueHex = spki.subjectPublicKey.valueBlock.valueHexView;
// Parse the public key ASN.1 structure
const asn1PublicKey = asn1js.fromBER(spkiValueHex);
if (asn1PublicKey.offset === -1) {
throw new Error('Error parsing public key ASN.1 structure');
}
// The public key is an RSAPublicKey structure
const rsaPublicKey = new RSAPublicKey({ schema: asn1PublicKey.result });
const modulusBytes = rsaPublicKey.modulus.valueBlock.valueHexView;
const modulusHex = Buffer.from(modulusBytes).toString('hex');
const exponentBigInt = rsaPublicKey.publicExponent.toBigInt();
const exponentDecimal = exponentBigInt.toString();
const actualBits = modulusBytes.length * 8;
const sigAlgParams = cert.signatureAlgorithm.algorithmParams;
const pssParams = new RSASSAPSSParams({ schema: sigAlgParams });
const hashAlgorithm = getFriendlyName(pssParams.hashAlgorithm.algorithmId);
const mgf = getFriendlyName(pssParams.maskGenAlgorithm.algorithmId);
return {
modulus: modulusHex,
exponent: exponentDecimal,
bits: actualBits.toString(),
hashAlgorithm: hashAlgorithm,
mgf: mgf,
saltLength: pssParams.saltLength.toString(),
};
}
export function getParamsECDSA(cert: Certificate): PublicKeyDetailsECDSA {
try {
const algorithmParams = cert.subjectPublicKeyInfo.algorithm.algorithmParams;
if (!algorithmParams) {
console.error('No algorithm params found');
return {
curve: 'Unknown',
params: {} as StandardCurve,
bits: 'Unknown',
x: 'Unknown',
y: 'Unknown',
};
}
let curveName,
bits,
x,
y = 'Unknown';
let curveParams: StandardCurve = {} as StandardCurve;
// Try to get the curve name from the OID
if (algorithmParams instanceof asn1js.ObjectIdentifier) {
const curveOid = algorithmParams.valueBlock.toString();
curveName = getFriendlyName(curveOid) || 'Unknown';
bits = getECDSACurveBits(curveName);
}
// If the OID of the curve is not present, we try to get the curve parameters and identify the curve from them
else {
const params = asn1js.fromBER(algorithmParams.valueBeforeDecodeView).result;
const valueBlock: any = params.valueBlock;
if (valueBlock.value && valueBlock.value.length >= 5) {
const curveParams: StandardCurve = {} as StandardCurve;
// Field ID (index 1)
const fieldId = valueBlock.value[1];
if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) {
const fieldType = fieldId.valueBlock.value[0];
const prime = fieldId.valueBlock.value[1];
//curveParams.fieldType = fieldType.valueBlock.toString();
curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex');
}
// Curve Coefficients (index 2)
const curveCoefficients = valueBlock.value[2];
if (
curveCoefficients &&
curveCoefficients.valueBlock &&
curveCoefficients.valueBlock.value
) {
const a = curveCoefficients.valueBlock.value[0];
const b = curveCoefficients.valueBlock.value[1];
curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex');
curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex');
}
// Base Point G (index 3)
const basePoint = valueBlock.value[3];
if (basePoint && basePoint.valueBlock) {
curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex');
}
// Order n (index 4)
const order = valueBlock.value[4];
if (order && order.valueBlock) {
curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex');
}
if (valueBlock.value.length >= 6) {
// Cofactor h (index 5)
const cofactor = valueBlock.value[5];
if (cofactor && cofactor.valueBlock) {
curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex');
}
} else {
curveParams.h = '01';
}
const identifiedCurve = identifyCurve(curveParams);
curveName = identifiedCurve;
bits = getECDSACurveBits(curveName);
} else {
if (valueBlock.value) {
console.log(valueBlock.value);
} else {
console.log('No value block found');
}
}
}
// Get the public key x and y parameters
const publicKeyBuffer = cert.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
if (publicKeyBuffer && curveName !== 'Unknown') {
const elliptic = initElliptic();
const ec = new elliptic.ec(getCurveForElliptic(curveName));
const key = ec.keyFromPublic(publicKeyBuffer);
x = key.getPublic().getX().toString('hex');
y = key.getPublic().getY().toString('hex');
}
return { curve: curveName, params: curveParams, bits: bits, x: x, y: y };
} catch (error) {
console.error('Error parsing EC parameters:', error);
return {
curve: 'Error',
params: {} as StandardCurve,
bits: 'Unknown',
x: 'Unknown',
y: 'Unknown',
};
}
}
export const getAuthorityKeyIdentifier = (cert: Certificate): string => {
const authorityKeyIdentifier = cert.extensions.find((ext) => ext.extnID === '2.5.29.35');
if (authorityKeyIdentifier) {
let akiValue = Buffer.from(authorityKeyIdentifier.extnValue.valueBlock.valueHexView).toString(
'hex'
);
akiValue = akiValue.replace(/^(?:3016)?(?:0414)?/, '');
// cur off the first 2 bytes
akiValue = akiValue.slice(4);
return akiValue;
}
return null;
};
export const getCircuitName = (
circuitMode: 'prove' | 'dsc' | 'vc_and_disclose',
signatureAlgorithm: string,
hashFunction: string,
domainParameter: string,
keyLength: string
) => {
const circuit = circuitNameFromMode[circuitMode];
if (circuit == 'vc_and_disclose') {
return 'vc_and_disclose';
}
if (circuit == 'dsc') {
return (
circuit +
'_' +
signatureAlgorithm +
'_' +
hashFunction +
'_' +
domainParameter +
'_' +
keyLength
);
}
return (
circuit +
'_' +
signatureAlgorithm +
'_' +
hashFunction +
'_' +
domainParameter +
'_' +
keyLength
);
};
export const getCircuitNameOld = (
circuitMode: Mode,
signatureAlgorithm: string,
hashFunction: string
) => {
const circuit = circuitNameFromMode[circuitMode];
if (circuit == 'vc_and_disclose') {
return 'vc_and_disclose';
} else if (signatureAlgorithm === 'ecdsa') {
return circuit + '_' + signatureAlgorithm + '_secp256r1_' + hashFunction;
} else {
return circuit + '_' + signatureAlgorithm + '_65537_' + hashFunction;
}
};
export function getHashAlgorithm(rawSignatureAlgorithm: string) {
const input = rawSignatureAlgorithm.toLowerCase();
const patterns = [/sha-?1/i, /sha-?256/i, /sha-?384/i, /sha-?512/i];
for (const pattern of patterns) {
const match = input.match(pattern);
if (match) {
// Remove any hyphens and return standardized format
return match[0].replace('-', '');
}
}
return 'unknown';
}

View File

@@ -1,53 +1,54 @@
import { asn1 } from "node-forge";
import * as asn1js from "asn1js";
import { Certificate } from "pkijs";
import { asn1 } from 'node-forge';
import * as asn1js from 'asn1js';
import { Certificate } from 'pkijs';
import { sha256 } from 'js-sha256';
export const getSubjectKeyIdentifier = (cert: Certificate): string => {
const subjectKeyIdentifier = cert.extensions.find(
(ext) => ext.extnID === '2.5.29.14'
const subjectKeyIdentifier = cert.extensions.find((ext) => ext.extnID === '2.5.29.14');
if (subjectKeyIdentifier) {
let skiValue = Buffer.from(subjectKeyIdentifier.extnValue.valueBlock.valueHexView).toString(
'hex'
);
if (subjectKeyIdentifier) {
let skiValue = Buffer.from(subjectKeyIdentifier.extnValue.valueBlock.valueHexView).toString('hex');
skiValue = skiValue.replace(/^(?:3016)?(?:0414)?/, '');
return skiValue
} else {
// do a sha1 of the certificate tbs
const crypto = require('crypto');
const sha1 = crypto.createHash('sha1');
sha1.update(cert.tbsView);
return sha1.digest('hex');
}
}
skiValue = skiValue.replace(/^(?:3016)?(?:0414)?/, '');
return skiValue;
} else {
// do a sha1 of the certificate tbs
const hash = sha256.create();
hash.update(cert.tbsView);
return hash.hex();
}
};
export const getAuthorityKeyIdentifier = (cert: Certificate): string => {
const authorityKeyIdentifierExt = cert.extensions.find(ext => ext.extnID === '2.5.29.35');
if (authorityKeyIdentifierExt) {
const extnValueHex = authorityKeyIdentifierExt.extnValue.valueBlock.valueHexView;
const asn1 = asn1js.fromBER(extnValueHex);
if (asn1.offset !== -1) {
const constructedValue = asn1.result.valueBlock as { value: Array<any> };
if (constructedValue.value) {
const keyIdentifierElement = constructedValue.value.find(
element => element.idBlock.tagClass === 3 && element.idBlock.tagNumber === 0
);
if (keyIdentifierElement) {
return Buffer.from(keyIdentifierElement.valueBlock.valueHexView).toString('hex');
}
}
const authorityKeyIdentifierExt = cert.extensions.find((ext) => ext.extnID === '2.5.29.35');
if (authorityKeyIdentifierExt) {
const extnValueHex = authorityKeyIdentifierExt.extnValue.valueBlock.valueHexView;
const asn1 = asn1js.fromBER(extnValueHex);
if (asn1.offset !== -1) {
const constructedValue = asn1.result.valueBlock as { value: Array<any> };
if (constructedValue.value) {
const keyIdentifierElement = constructedValue.value.find(
(element) => element.idBlock.tagClass === 3 && element.idBlock.tagNumber === 0
);
if (keyIdentifierElement) {
return Buffer.from(keyIdentifierElement.valueBlock.valueHexView).toString('hex');
}
}
}
return '';
}
return '';
};
export function getIssuerCountryCode(cert: Certificate): string {
const issuerRDN = cert.issuer.typesAndValues;
let issuerCountryCode = '';
for (const rdn of issuerRDN) {
if (rdn.type === '2.5.4.6') { // OID for Country Name
issuerCountryCode = rdn.value.valueBlock.value;
break;
}
const issuerRDN = cert.issuer.typesAndValues;
let issuerCountryCode = '';
for (const rdn of issuerRDN) {
if (rdn.type === '2.5.4.6') {
// OID for Country Name
issuerCountryCode = rdn.value.valueBlock.value;
break;
}
return issuerCountryCode.toUpperCase();
}
}
return issuerCountryCode.toUpperCase();
}

View File

@@ -1,111 +0,0 @@
import * as path from 'path';
import jsrsasign from 'jsrsasign';
import * as asn1 from 'asn1.js';
import fs from 'fs';
export const RSAPublicKey = asn1.define('RSAPublicKey', function () {
this.seq().obj(this.key('n').int(), this.key('e').int());
});
export function isRsaPublicKey(key) {
return key.type === 'RSA' || key.type === 'RSA-PSS';
}
export function getPublicKey(certificate) {
const publicKeyInfo = certificate.getPublicKeyHex();
try {
// Try to parse the public key as ASN.1
const publicKeyAsn1 = asn1.define('PublicKey', function () {
this.seq().obj(
this.key('algorithm')
.seq()
.obj(this.key('algorithmId').objid(), this.key('parameters').optional().any()),
this.key('publicKey').bitstr()
);
});
const parsed = publicKeyAsn1.decode(Buffer.from(publicKeyInfo, 'hex'), 'der');
const publicKeyBuffer = parsed.publicKey.data;
// Parse the RSA public key
const rsaPublicKey = RSAPublicKey.decode(publicKeyBuffer, 'der');
return {
n: new jsrsasign.BigInteger(rsaPublicKey.n.toString('hex'), 16),
e: new jsrsasign.BigInteger(rsaPublicKey.e.toString('hex'), 16),
type: 'RSA',
};
} catch (e) {
console.error('Error parsing public key:', e);
}
// If parsing fails, fall back to manual extraction
const modulus = extractModulus(publicKeyInfo);
if (modulus) {
return { n: new jsrsasign.BigInteger(modulus, 16), type: 'RSA' };
}
throw new Error('Unable to extract public key');
}
function extractModulus(publicKeyInfo: string): string | null {
// RSA OID
const rsaOid = '2a864886f70d010101';
// RSA-PSS OID
const rsaPssOid = '2a864886f70d01010a';
let offset = publicKeyInfo.indexOf(rsaOid);
if (offset === -1) {
offset = publicKeyInfo.indexOf(rsaPssOid);
}
if (offset === -1) {
return null;
}
// Skip OID and move to the bit string
offset = publicKeyInfo.indexOf('03', offset);
if (offset === -1) {
return null;
}
// Skip bit string tag and length
offset += 4;
// Extract modulus
const modulusStart = publicKeyInfo.indexOf('02', offset) + 2;
const modulusLength = parseInt(publicKeyInfo.substr(modulusStart, 2), 16) * 2;
const modulus = publicKeyInfo.substr(modulusStart + 2, modulusLength);
return modulus;
}
export function readCertificate(filePath: string): jsrsasign.X509 {
const certPem = fs.readFileSync(filePath, 'utf8');
const certificate = new jsrsasign.X509();
certificate.readCertPEM(certPem);
return certificate;
}
export function getTBSCertificate(certificate: jsrsasign.X509): Buffer {
// console.log("Certificate:", certificate);
const certASN1 = certificate.getParam();
// console.log("certASN1:", certASN1);
if (!certASN1) {
console.error('Failed to get certificate parameters');
throw new Error('Invalid certificate structure');
}
// Extract the TBS part directly from the certificate's hex representation
const certHex = certificate.hex;
const tbsStartIndex = certHex.indexOf('30') + 2; // Start after the first sequence tag
const tbsLength = parseInt(certHex.substr(tbsStartIndex, 2), 16) * 2 + 2; // Length in bytes * 2 for hex + 2 for length field
const tbsHex = certHex.substr(tbsStartIndex - 2, tbsLength); // Include the sequence tag
// console.log("TBS Hex:", tbsHex);
return Buffer.from(tbsHex, 'hex');
}

View File

@@ -1,149 +0,0 @@
export interface StandardCurve {
name: string;
p: string;
a: string;
b: string;
G: string;
n: string;
h: string;
}
export const standardCurves: StandardCurve[] = [
{
name: 'secp256r1',
p: 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF',
a: 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC',
b: '5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B',
G: '046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5',
n: 'FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551',
h: '01',
},
{
name: 'secp384r1',
p: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF',
a: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC',
b: 'B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF',
G: '04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F',
n: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973',
h: '01',
},
{
name: 'secp521r1',
p: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
a: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC',
b: '0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00',
G: '0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650',
n: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409',
h: '01',
},
{
name: 'brainpoolP256r1',
p: 'A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377',
a: '7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9',
b: '26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6',
G: '048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997',
n: 'A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7',
h: '01',
},
{
name: 'brainpoolP384r1',
p: '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53',
a: '7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826',
b: '04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11',
G: '041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315',
n: '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565',
h: '01',
},
{
name: 'brainpoolP512r1',
p: 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3',
a: '7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA',
b: '3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723',
G: '0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892',
n: 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069',
h: '01',
},
];
export function normalizeHex(hex: string): string {
return hex.toLowerCase().replace(/^0x/, '').replace(/^00/, '');
}
export function identifyCurve(params: any): string {
const normalizedParams = {
p: normalizeHex(params.p),
a: normalizeHex(params.a),
b: normalizeHex(params.b),
G: normalizeHex(params.G),
n: normalizeHex(params.n),
h: normalizeHex(params.h),
};
for (const curve of standardCurves) {
if (
normalizedParams.p === normalizeHex(curve.p) &&
normalizedParams.a === normalizeHex(curve.a) &&
normalizedParams.b === normalizeHex(curve.b) &&
normalizedParams.G === normalizeHex(curve.G) &&
normalizedParams.n === normalizeHex(curve.n) &&
normalizedParams.h === normalizeHex(curve.h)
) {
return curve.name;
}
}
return 'Unknown curve';
}
export function getNamedCurve(oid: string): string {
const curves = {
'1.3.36.3.3.2.8.1.1.5': 'brainpoolP224r1',
'1.2.840.10045.3.1.7': 'secp256r1',
'1.3.132.0.34': 'secp384r1',
'1.3.132.0.35': 'secp521r1',
'1.3.36.3.3.2.8.1.1.7': 'brainpoolP256r1',
'1.3.36.3.3.2.8.1.1.11': 'brainpoolP384r1',
'1.3.36.3.3.2.8.1.1.13': 'brainpoolP512r1',
// Add more curve OIDs as needed
};
if (!curves[oid]) {
throw new Error('Invalid curve: ' + oid);
}
return curves[oid];
}
export function getCurveForElliptic(curveName: string): string {
const curves = {
secp256r1: 'p256',
secp384r1: 'p384',
secp521r1: 'p521',
brainpoolP224r1: 'brainpoolP224r1',
brainpoolP256r1: 'brainpoolP256r1',
brainpoolP384r1: 'brainpoolP384r1',
brainpoolP512r1: 'brainpoolP512r1',
};
if (!curves[curveName]) {
throw new Error('Invalid curve: ' + curveName);
}
return curves[curveName];
}
export function getECDSACurveBits(curveName: string): string {
const curveBits: { [key: string]: number } = {
secp256r1: 256,
secp384r1: 384,
secp521r1: 521,
brainpoolP256r1: 256,
brainpoolP384r1: 384,
brainpoolP512r1: 512,
'secp256r1 (NIST P-256)': 256,
'secp384r1 (NIST P-384)': 384,
'secp521r1 (NIST P-521)': 521,
};
if (curveName in curveBits) {
return curveBits[curveName].toString();
}
console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`);
return 'unknown';
}

View File

@@ -1,40 +0,0 @@
import { StandardCurve } from './curves';
export interface CertificateData {
id: string;
issuer: string;
validity: {
notBefore: string;
notAfter: string;
};
subjectKeyIdentifier: string;
signatureAlgorithm: string;
hashFunction: string;
publicKeyDetails:
| PublicKeyDetailsRSA
| PublicKeyDetailsECDSA
| PublicKeyDetailsRSAPSS
| undefined;
rawPem: string;
rawTxt: string;
}
export interface PublicKeyDetailsRSA {
modulus: string;
exponent: string;
bits: string;
}
export interface PublicKeyDetailsRSAPSS extends PublicKeyDetailsRSA {
hashFunction: string;
mgf: string;
saltLength: string;
}
export interface PublicKeyDetailsECDSA {
curve: string;
params: StandardCurve;
bits: string;
x: string;
y: string;
}

View File

@@ -1,291 +0,0 @@
import * as asn1 from 'asn1js';
import { Certificate } from 'pkijs';
import { getHashLen } from '../utils';
import elliptic from 'elliptic';
import { parseRsaPublicKey, parseRsaPssPublicKey, parseECParameters } from './publicKeyDetails';
import { PublicKeyDetailsRSAPSS } from './dataStructure';
import { getNamedCurve } from './curves';
import { circuitNameFromMode } from '../../constants/constants';
import { Mode } from '../appType';
if (typeof global.Buffer === 'undefined') {
global.Buffer = require('buffer').Buffer;
}
export function parseCertificate(pem: string) {
const cert = getCertificateFromPem(pem);
let { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails(
cert.signatureAlgorithm.algorithmId
);
const subjectPublicKeyInfo = cert.subjectPublicKeyInfo;
const subjectKeyIdentifier = getSubjectKeyIdentifier(cert);
const authorityKeyIdentifier = getAuthorityKeyIdentifier(cert);
let publicKeyDetails: any;
switch (signatureAlgorithm) {
case 'rsa':
publicKeyDetails = parseRsaPublicKey(subjectPublicKeyInfo);
if (!publicKeyDetails) {
console.log('\x1b[33mRSA public key not found, probably ECDSA certificate\x1b[0m');
}
break;
case 'rsapss':
const rsaPssParams = cert.signatureAlgorithm.algorithmParams;
publicKeyDetails = parseRsaPssPublicKey(subjectPublicKeyInfo, rsaPssParams);
if (publicKeyDetails) {
hashFunction = (publicKeyDetails as PublicKeyDetailsRSAPSS).hashFunction;
}
if (!publicKeyDetails) {
console.log('\x1b[33mRSA-PSS public key not found\x1b[0m');
}
break;
case 'ecdsa':
publicKeyDetails = parseECParameters(subjectPublicKeyInfo);
if (!publicKeyDetails) {
console.log('\x1b[33mECDSA public key not found\x1b[0m');
}
break;
default:
console.log('\x1b[33mUnknown signature algorithm: \x1b[0m', signatureAlgorithm);
}
const hashLen = getHashLen(hashFunction);
return {
signatureAlgorithm,
hashFunction,
hashLen,
subjectKeyIdentifier,
authorityKeyIdentifier,
...publicKeyDetails,
};
}
export const getCircuitName = (
circuitMode: 'prove' | 'dsc' | 'vc_and_disclose',
signatureAlgorithm: string,
hashFunction: string,
domainParameter: string,
keyLength: string
) => {
const circuit = circuitNameFromMode[circuitMode];
if (circuit == 'vc_and_disclose') {
return 'vc_and_disclose';
}
if (circuit == 'dsc') {
return (
circuit +
'_' +
signatureAlgorithm +
'_' +
hashFunction +
'_' +
domainParameter +
'_' +
keyLength
);
}
return (
circuit +
'_' +
signatureAlgorithm +
'_' +
hashFunction +
'_' +
domainParameter +
'_' +
keyLength
);
};
export const getCircuitNameOld = (
circuitMode: Mode,
signatureAlgorithm: string,
hashFunction: string
) => {
const circuit = circuitNameFromMode[circuitMode];
if (circuit == 'vc_and_disclose') {
return 'vc_and_disclose';
} else if (signatureAlgorithm === 'ecdsa') {
return circuit + '_' + signatureAlgorithm + '_secp256r1_' + hashFunction;
} else {
return circuit + '_' + signatureAlgorithm + '_65537_' + hashFunction;
}
};
export function getSignatureAlgorithmDetails(oid: string): {
signatureAlgorithm: string;
hashFunction: string;
} {
const details = {
'1.2.840.113549.1.1.5': {
signatureAlgorithm: 'rsa',
hashFunction: 'sha1',
domainParameter: '65537',
keyLength: '2048',
},
'1.2.840.113549.1.1.11': {
signatureAlgorithm: 'rsa',
hashFunction: 'sha256',
domainParameter: '65537',
keyLength: '2048',
},
'1.2.840.113549.1.1.12': {
signatureAlgorithm: 'rsa',
hashFunction: 'sha384',
domainParameter: '65537',
keyLength: '2048',
},
'1.2.840.113549.1.1.13': {
signatureAlgorithm: 'rsa',
hashFunction: 'sha512',
domainParameter: '65537',
keyLength: '2048',
},
// rsapss
'1.2.840.113549.1.1.10': {
signatureAlgorithm: 'rsapss',
hashFunction: 'sha256',
domainParameter: '65537',
keyLength: '2048',
}, // TODO: detect which hash function is used (not always sha256)
// ecdsa
'1.2.840.10045.4.1': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha1',
domainParameter: 'secp256r1',
keyLength: '256',
},
'1.2.840.10045.4.3.1': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha224',
domainParameter: 'secp256r1',
keyLength: '256',
},
'1.2.840.10045.4.3.2': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha256',
domainParameter: 'secp256r1',
keyLength: '256',
},
'1.2.840.10045.4.3.3': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha384',
domainParameter: 'secp384r1',
keyLength: '384',
},
'1.2.840.10045.4.3.4': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha512',
domainParameter: 'secp521r1',
keyLength: '521',
},
};
return details[oid] || { signatureAlgorithm: `Unknown (${oid})`, hashFunction: 'Unknown' };
}
export function gethashFunctionName(oid: string): string {
const hashFunctions = {
'1.3.14.3.2.26': 'sha1',
'2.16.840.1.101.3.4.2.1': 'sha256',
'2.16.840.1.101.3.4.2.2': 'sha384',
'2.16.840.1.101.3.4.2.3': 'sha512',
};
return hashFunctions[oid] || `Unknown (${oid})`;
}
export function getCertificateFromPem(pemContent: string): Certificate {
const certBuffer = Buffer.from(
pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1.fromBER(certBuffer);
return new Certificate({ schema: asn1Data.result });
}
export const getSubjectKeyIdentifier = (cert: Certificate): string => {
const subjectKeyIdentifier = cert.extensions.find(
(ext) => ext.extnID === '2.5.29.14' // OID for Subject Key Identifier
);
if (subjectKeyIdentifier) {
let skiValue = Buffer.from(subjectKeyIdentifier.extnValue.valueBlock.valueHexView).toString(
'hex'
);
skiValue = skiValue.replace(/^(?:3016)?(?:0414)?/, '');
return skiValue;
} else {
return null;
}
};
export const getAuthorityKeyIdentifier = (cert: Certificate): string => {
const authorityKeyIdentifier = cert.extensions.find((ext) => ext.extnID === '2.5.29.35');
if (authorityKeyIdentifier) {
let akiValue = Buffer.from(authorityKeyIdentifier.extnValue.valueBlock.valueHexView).toString(
'hex'
);
akiValue = akiValue.replace(/^(?:3016)?(?:0414)?/, '');
// cur off the first 2 bytes
akiValue = akiValue.slice(4);
return akiValue;
}
return null;
};
export function getIssuerCountryCode(cert: Certificate): string {
const issuerRDN = cert.issuer.typesAndValues;
let issuerCountryCode = '';
for (const rdn of issuerRDN) {
if (rdn.type === '2.5.4.6') {
// OID for Country Name
issuerCountryCode = rdn.value.valueBlock.value;
break;
}
}
return issuerCountryCode.toUpperCase();
}
export const parseDSC = (pemContent: string) => {
const certBuffer = Buffer.from(
pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1.fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data.result });
const signatureAlgorithmOid = cert.signatureAlgorithm.algorithmId;
const { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails(signatureAlgorithmOid);
const hashLen = getHashLen(hashFunction);
let publicKeyDetails;
if (signatureAlgorithm === 'ecdsa') {
const subjectPublicKeyInfo = cert.subjectPublicKeyInfo;
const algorithmParams = subjectPublicKeyInfo.algorithm.algorithmParams;
const curveOid = asn1.fromBER(algorithmParams.valueBeforeDecode).result.valueBlock.toString();
const curve = getNamedCurve(curveOid);
const publicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384';
const ec = new elliptic.ec(curveForElliptic);
const key = ec.keyFromPublic(publicKeyBuffer);
const x = key.getPublic().getX().toString('hex');
const y = key.getPublic().getY().toString('hex');
const fieldSizeMap: { [key: string]: number } = {
secp256r1: 256,
secp384r1: 384,
};
const bits = fieldSizeMap[curve];
publicKeyDetails = { curve, x, y, bits };
} else {
const publicKey = cert.subjectPublicKeyInfo.subjectPublicKey;
const asn1PublicKey = asn1.fromBER(publicKey.valueBlock.valueHexView);
const rsaPublicKey = asn1PublicKey.result.valueBlock;
const modulus = Buffer.from((rsaPublicKey as any).value[0].valueBlock.valueHexView).toString(
'hex'
);
const exponent = Buffer.from((rsaPublicKey as any).value[1].valueBlock.valueHexView).toString(
'hex'
);
const bits = Buffer.from(modulus, 'hex').length * 8;
publicKeyDetails = { modulus, exponent, bits };
}
return { signatureAlgorithm, hashFunction, hashLen, ...publicKeyDetails };
};

View File

@@ -1,351 +0,0 @@
import { fromBER, BitString } from 'asn1js';
import * as asn1 from 'asn1js';
import * as forge from 'node-forge';
import {
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
} from './dataStructure';
import {
identifyCurve,
StandardCurve,
getNamedCurve,
getECDSACurveBits,
getCurveForElliptic,
} from './curves';
import { gethashFunctionName } from './handleCertificate';
import elliptic from 'elliptic';
import hash from 'hash.js';
const curves = elliptic.curves;
const PresetCurve = elliptic.curves.PresetCurve;
function defineCurve(name, options) {
Object.defineProperty(curves, name, {
configurable: true,
enumerable: true,
get: function () {
var curve = new PresetCurve(options);
Object.defineProperty(curves, name, {
configurable: true,
enumerable: true,
value: curve,
});
return curve;
},
});
}
defineCurve('brainpoolP224r1', {
type: 'short',
prime: null,
p: 'd7c134aa 26436686 2a183025 75d1d787 b09f0757 97da89f5 7ec8c0ff',
a: '68a5e62c a9ce6c1c 299803a6 c1530b51 4e182ad8 b0042a59 cad29f43',
b: '2580f63c cfe44138 870713b1 a92369e3 3e2135d2 66dbb372 386c400b',
n: 'd7c134aa 26436686 2a183025 75d0fb98 d116bc4b 6ddebca3 a5a7939f',
hash: hash.sha1,
gRed: false,
g: [
'0d9029ad 2c7e5cf4 340823b2 a87dc68c 9e4ce317 4c1e6efd ee12c07d',
'58aa56f7 72c0726f 24c6b89e 4ecdac24 354b9e99 caa3f6d3 761402cd',
],
});
defineCurve('brainpoolP256r1', {
type: 'short',
prime: null,
p: 'a9fb57db a1eea9bc 3e660a90 9d838d72 6e3bf623 d5262028 2013481d 1f6e5377',
a: '7d5a0975 fc2c3057 eef67530 417affe7 fb8055c1 26dc5c6c e94a4b44 f330b5d9',
b: '26dc5c6c e94a4b44 f330b5d9 bbd77cbf 95841629 5cf7e1ce 6bccdc18 ff8c07b6',
n: 'a9fb57db a1eea9bc 3e660a90 9d838d71 8c397aa3 b561a6f7 901e0e82 974856a7',
hash: hash.sha256,
gRed: false,
g: [
'8bd2aeb9 cb7e57cb 2c4b482f fc81b7af b9de27e1 e3bd23c2 3a4453bd 9ace3262',
'547ef835 c3dac4fd 97f8461a 14611dc9 c2774513 2ded8e54 5c1d54c7 2f046997',
],
});
defineCurve('brainpoolP384r1', {
type: 'short',
prime: null,
p: '8cb91e82 a3386d28 0f5d6f7e 50e641df 152f7109 ed5456b4 12b1da19 7fb71123 acd3a729 901d1a71 87470013 3107ec53',
a: '7bc382c6 3d8c150c 3c72080a ce05afa0 c2bea28e 4fb22787 139165ef ba91f90f 8aa5814a 503ad4eb 04a8c7dd 22ce2826',
b: '04a8c7dd 22ce2826 8b39b554 16f0447c 2fb77de1 07dcd2a6 2e880ea5 3eeb62d5 7cb43902 95dbc994 3ab78696 fa504c11',
n: '8cb91e82 a3386d28 0f5d6f7e 50e641df 152f7109 ed5456b3 1f166e6c ac0425a7 cf3ab6af 6b7fc310 3b883202 e9046565',
hash: hash.sha384,
gRed: false,
g: [
'1d1c64f0 68cf45ff a2a63a81 b7c13f6b 8847a3e7 7ef14fe3 db7fcafe 0cbd10e8 e826e034 36d646aa ef87b2e2 47d4af1e',
'8abe1d75 20f9c2a4 5cb1eb8e 95cfd552 62b70b29 feec5864 e19c054f f9912928 0e464621 77918111 42820341 263c5315',
],
});
defineCurve('brainpoolP512r1', {
type: 'short',
prime: null,
p:
'AADD9DB8 DBE9C48B 3FD4E6AE 33C9FC07 CB308DB3 B3C9D20E D6639CCA 70330871' +
'7D4D9B00 9BC66842 AECDA12A E6A380E6 2881FF2F 2D82C685 28AA6056 583A48F3',
a:
'7830A331 8B603B89 E2327145 AC234CC5 94CBDD8D 3DF91610 A83441CA EA9863BC' +
'2DED5D5A A8253AA1 0A2EF1C9 8B9AC8B5 7F1117A7 2BF2C7B9 E7C1AC4D 77FC94CA',
b:
'3DF91610 A83441CA EA9863BC 2DED5D5A A8253AA1 0A2EF1C9 8B9AC8B5 7F1117A7' +
'2BF2C7B9 E7C1AC4D 77FC94CA DC083E67 984050B7 5EBAE5DD 2809BD63 8016F723',
n:
'AADD9DB8 DBE9C48B 3FD4E6AE 33C9FC07 CB308DB3 B3C9D20E D6639CCA 70330870' +
'553E5C41 4CA92619 41866119 7FAC1047 1DB1D381 085DDADD B5879682 9CA90069',
hash: hash.sha512,
gRed: false,
g: [
'81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D009' +
'8EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822',
'7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F81' +
'11B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892',
],
});
export function parseRsaPublicKey(subjectPublicKeyInfo: any): PublicKeyDetailsRSA {
const publicKey = subjectPublicKeyInfo.subjectPublicKey;
const asn1PublicKey = fromBER(publicKey.valueBlock.valueHexView);
const rsaPublicKey = asn1PublicKey.result.valueBlock;
if (
rsaPublicKey &&
(rsaPublicKey as any).value &&
(rsaPublicKey as any).value[0] &&
(rsaPublicKey as any).value[1]
) {
const modulusAsn1 = (rsaPublicKey as any).value[0];
const exponentAsn1 = (rsaPublicKey as any).value[1];
const modulusHex = Buffer.from(modulusAsn1.valueBlock.valueHexView).toString('hex');
const exponentHex = Buffer.from(exponentAsn1.valueBlock.valueHexView).toString('hex');
const publicKeyForge = forge.pki.rsa.setPublicKey(
new forge.jsbn.BigInteger(modulusHex, 16),
new forge.jsbn.BigInteger(exponentHex, 16)
);
const publicKeyDetailsRSA: PublicKeyDetailsRSA = {
modulus: publicKeyForge.n.toString(16),
exponent: publicKeyForge.e.toString(10),
bits: publicKeyForge.n.bitLength().toString(),
};
return publicKeyDetailsRSA;
} else {
return null;
}
}
export function parseECParameters(publicKeyInfo: any): PublicKeyDetailsECDSA {
try {
const algorithmParams = publicKeyInfo.algorithm.algorithmParams;
if (!algorithmParams) {
console.error('\x1b[31mNo algorithm params found\x1b[0m');
return null;
}
// get x and y;
const curveOid = asn1.fromBER(algorithmParams.valueBeforeDecode).result.valueBlock.toString();
const curve = getNamedCurve(curveOid);
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = getCurveForElliptic(curve);
const ec = new elliptic.ec(curveForElliptic);
const key = ec.keyFromPublic(publicKeyBuffer);
const x = key.getPublic().getX().toString('hex');
const y = key.getPublic().getY().toString('hex');
const fieldSizeMap: { [key: string]: number } = {
secp256r1: 256,
secp384r1: 384,
brainpoolP224r1: 224,
brainpoolP256r1: 256,
brainpoolP384r1: 384,
brainpoolP512r1: 512,
};
const bits = fieldSizeMap[curve];
const params = asn1.fromBER(algorithmParams.valueBeforeDecodeView).result;
const valueBlock: any = params.valueBlock;
let curveParams: StandardCurve = {} as StandardCurve;
// if (valueBlock.value && valueBlock.value.length >= 6) {
// // Field ID (index 1)
// const curveParams = {} as StandardCurve;
// const fieldId = valueBlock.value[1];
// if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) {
// const fieldType = fieldId.valueBlock.value[0];
// const prime = fieldId.valueBlock.value[1];
// //curveParams.fieldType = fieldType.valueBlock.toString();
// curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex');
// }
// // Curve Coefficients (index 2)
// const curveCoefficients = valueBlock.value[2];
// if (curveCoefficients && curveCoefficients.valueBlock && curveCoefficients.valueBlock.value) {
// const a = curveCoefficients.valueBlock.value[0];
// const b = curveCoefficients.valueBlock.value[1];
// curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex');
// curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex');
// }
// // Base Point G (index 3)
// const basePoint = valueBlock.value[3];
// if (basePoint && basePoint.valueBlock) {
// curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex');
// }
// // Order n (index 4)
// const order = valueBlock.value[4];
// if (order && order.valueBlock) {
// curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex');
// }
// // Cofactor h (index 5)
// const cofactor = valueBlock.value[5];
// if (cofactor && cofactor.valueBlock) {
// curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex');
// }
// if (curveParams.p && curveParams.a && curveParams.b && curveParams.G && curveParams.n && curveParams.h) {
// const identifiedCurve = identifyCurve(curveParams);
// }
// } else {
// if (valueBlock.value) {
// if (algorithmParams.idBlock.tagNumber === 6) {
// console.log('\x1b[33malgorithmParams.idBlock.tagNumber === 6, looking for algorithmParams.valueBlock\x1b[0m');
// const curveOid = algorithmParams.valueBlock.toString();
// const curveName = getNamedCurve(curveOid);
// // console.error('\x1b[33mCurve OID:', curveName, '\x1b[0m');
// return { curve: curveName, params: {} as StandardCurve, bits: getECDSACurveBits(curveName) };
// }
// else {
// console.log('\x1b[31malgorithmParams.idBlock.tagNumber !== 6\x1b[0m');
// }
// }
// else {
// console.log('\x1b[31mvalue block is not defined\x1b[0m');
// }
// }
const publicKeyDetailsECDSA: PublicKeyDetailsECDSA = {
curve: curve,
params: curveParams,
bits: bits.toString(),
x: x,
y: y,
};
return publicKeyDetailsECDSA;
} catch (error) {
console.error('Error parsing EC parameters:', error);
}
}
export function parseRsaPssParams(params: any): {
hashFunction: string;
mgf: string;
saltLength: string;
} {
try {
const algorithmParams = asn1.fromBER(params.valueBeforeDecodeView);
const sequence = algorithmParams.result;
let hashFunction = 'Unknown';
let mgf = 'Unknown';
let saltLength = 'Unknown';
// Parse hash algorithm
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[0]) {
const hashFunctionSequence = (sequence.valueBlock as any).value[0].valueBlock.value[0];
const hashFunctionOid = hashFunctionSequence.valueBlock.value[0].valueBlock.toString();
hashFunction = gethashFunctionName(hashFunctionOid);
}
// Parse MGF
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[1]) {
const mgfSequence = (sequence.valueBlock as any).value[1].valueBlock.value[0];
const mgfOid = mgfSequence.valueBlock.value[0].valueBlock.toString();
mgf = mgfOid === '1.2.840.113549.1.1.8' ? 'MGF1' : `Unknown (${mgfOid})`;
}
// console.log((sequence.valueBlock as any).value[0].valueBlock);
// console.log((sequence.valueBlock as any).value[1].valueBlock);
// console.log((sequence.valueBlock as any).value[2].valueBlock);
// Parse salt length
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[2]) {
const saltLengthContainer = (sequence.valueBlock as any).value[2];
if (saltLengthContainer.valueBlock && saltLengthContainer.valueBlock.value) {
const rawSaltLength = saltLengthContainer.valueBlock.value[0];
if (typeof rawSaltLength === 'number') {
saltLength = rawSaltLength.toString();
} else if (
rawSaltLength &&
rawSaltLength.valueBlock &&
rawSaltLength.valueBlock.valueHexView
) {
const saltLengthValue = rawSaltLength.valueBlock.valueHexView[0];
saltLength = saltLengthValue.toString();
} else {
console.error('\x1b[31mUnable to parse salt length\x1b[0m');
}
} else {
console.log('\x1b[31mSalt length not found\x1b[0m');
}
}
return { hashFunction, mgf, saltLength };
} catch (error) {
console.error('Error parsing RSA-PSS parameters:', error);
return { hashFunction: 'Unknown', mgf: 'Unknown', saltLength: 'Unknown' };
}
}
export function parseRsaPssPublicKey(
subjectPublicKeyInfo: any,
rsaPssParams: any
): PublicKeyDetailsRSAPSS {
let hashFunction = 'Unknown';
let mgf = 'Unknown';
let saltLength = 'Unknown';
if (rsaPssParams) {
const parsedParams = parseRsaPssParams(rsaPssParams);
hashFunction = parsedParams.hashFunction;
mgf = parsedParams.mgf;
saltLength = parsedParams.saltLength;
} else {
console.log('\x1b[31mRSA-PSS parameters not found\x1b[0m');
}
// Add PublicKeyDetails for RSA-PSS
const publicKey = subjectPublicKeyInfo.subjectPublicKey;
const asn1PublicKey = fromBER(publicKey.valueBlock.valueHexView);
const rsaPublicKey = asn1PublicKey.result.valueBlock;
if (
rsaPublicKey &&
(rsaPublicKey as any).value &&
(rsaPublicKey as any).value[0] &&
(rsaPublicKey as any).value[1]
) {
const modulusAsn1 = (rsaPublicKey as any).value[0];
const exponentAsn1 = (rsaPublicKey as any).value[1];
const modulusHex = Buffer.from(modulusAsn1.valueBlock.valueHexView).toString('hex');
const exponentHex = Buffer.from(exponentAsn1.valueBlock.valueHexView).toString('hex');
const publicKeyForge = forge.pki.rsa.setPublicKey(
new forge.jsbn.BigInteger(modulusHex, 16),
new forge.jsbn.BigInteger(exponentHex, 16)
);
const PublicKeyDetailsRSAPSS: PublicKeyDetailsRSAPSS = {
modulus: publicKeyForge.n.toString(16),
exponent: publicKeyForge.e.toString(10),
bits: publicKeyForge.n.bitLength().toString(),
hashFunction,
mgf,
saltLength,
};
return PublicKeyDetailsRSAPSS;
} else {
return null;
}
}

View File

@@ -0,0 +1,49 @@
import { PassportData } from './types';
import { parsePassportData } from './parsePassportData';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import {
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
} from './certificate_parsing/dataStructure';
export function getCircuitNameFromPassportData(passportData: PassportData) {
const passportMetadata = parsePassportData(passportData);
const parsedDsc = parseCertificateSimple(passportData.dsc);
const dgHashAlgo = passportMetadata.dg1HashFunction;
const eContentHashAlgo = passportMetadata.eContentHashFunction;
const signedAttrHashAlgo = passportMetadata.signedAttrHashFunction;
const sigAlg = passportMetadata.signatureAlgorithm;
if (parsedDsc.signatureAlgorithm === 'ecdsa') {
const curve = (parsedDsc.publicKeyDetails as PublicKeyDetailsECDSA).curve;
return `prove_${dgHashAlgo}_${eContentHashAlgo}_${signedAttrHashAlgo}_${sigAlg}_${curve}`;
} else if (parsedDsc.signatureAlgorithm === 'rsa') {
const exponent = (parsedDsc.publicKeyDetails as PublicKeyDetailsRSA).exponent;
const bits = (parsedDsc.publicKeyDetails as PublicKeyDetailsRSA).bits;
if (parseInt(bits) <= 4096) {
return `prove_${dgHashAlgo}_${eContentHashAlgo}_${signedAttrHashAlgo}_${sigAlg}_${exponent}_${4096}`;
} else {
throw new Error(`Unsupported key length: ${bits}`);
}
} else if (parsedDsc.signatureAlgorithm === 'rsapss') {
const exponent = (parsedDsc.publicKeyDetails as PublicKeyDetailsRSA).exponent;
const saltLength = (parsedDsc.publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength;
const bits = (parsedDsc.publicKeyDetails as PublicKeyDetailsRSAPSS).bits;
if (parseInt(bits) <= 4096) {
return `prove_${dgHashAlgo}_${eContentHashAlgo}_${signedAttrHashAlgo}_${sigAlg}_${exponent}_${saltLength}_${4096}`;
} else {
throw new Error(`Unsupported key length: ${bits}`);
}
} else {
throw new Error('Unsupported signature algorithm');
}
}
export function getCurveOrExponent(dsc: any) {
const parsedDsc = parseCertificateSimple(dsc);
if (parsedDsc.signatureAlgorithm === 'ecdsa') {
return (parsedDsc.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
return (parsedDsc.publicKeyDetails as PublicKeyDetailsRSA).exponent;
}

View File

@@ -1,23 +1,17 @@
import { shaPad } from './shaPad';
import * as forge from 'node-forge';
import {
bytesToBigDecimal,
extractRSFromSignature,
getNAndK,
getNAndKCSCA,
hexToDecimal,
splitToWords,
} from './utils';
import { bytesToBigDecimal, getNAndK, getNAndKCSCA, hexToDecimal, splitToWords } from './utils';
import { CSCA_TREE_DEPTH, MODAL_SERVER_ADDRESS } from '../constants/constants';
import { poseidon2 } from 'poseidon-lite';
import { IMT } from '@openpassport/zk-kit-imt';
import serialized_csca_tree from '../../pubkeys/serialized_csca_tree.json';
import axios from 'axios';
import { parseCertificate, parseCertificateSimple } from './certificate_parsing/parseCertificate';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import { getLeafCSCA } from './pubkeyTree';
import { SKI_PEM, SKI_PEM_DEV } from '../constants/skiPem';
import { CertificateData, PublicKeyDetailsRSA } from './certificate_parsing/dataStructure';
import { formatInput } from './generateInputs';
import { SignatureAlgorithm } from './types';
export function findStartIndex(modulus: string, messagePadded: Uint8Array): number {
const modulusNumArray = [];
@@ -64,41 +58,42 @@ export function generateCircuitInputsDSC(
dscTbsCertBytes.map((byte) => parseInt(byte.toString(16), 16))
);
const {
signatureAlgorithm,
hashFunction,
authorityKeyIdentifier,
publicKeyDetails
} = parseCertificateSimple(dscCertificate);
console.log("authorityKeyIdentifier", authorityKeyIdentifier);
const { signatureAlgorithm, hashAlgorithm, authorityKeyIdentifier, publicKeyDetails } =
parseCertificateSimple(dscCertificate);
console.log('authorityKeyIdentifier', authorityKeyIdentifier);
let dsc_message_padded;
let dsc_messagePaddedLen;
[dsc_message_padded, dsc_messagePaddedLen] = shaPad(dscTbsCertUint8Array, max_cert_bytes);
const { n, k } = getNAndK(signatureAlgorithm);
console.log('signatureAlgorithm: ', signatureAlgorithm);
const { n, k } = getNAndK(signatureAlgorithm as SignatureAlgorithm);
const dscSignature = dscCert.signature;
const encryptedDigest = Array.from(forge.util.createBuffer(dscSignature).getBytes(), (char) =>
char.charCodeAt(0)
);
let pubKey_dsc, signature, startIndex, dsc_message_padded_formatted, dsc_messagePaddedLen_formatted: any;
let pubKey_dsc,
signature,
startIndex,
dsc_message_padded_formatted,
dsc_messagePaddedLen_formatted: any;
let curve, exponent;
if (signatureAlgorithm === 'rsa' || signatureAlgorithm === 'rsapss') {
const modulus = publicKeyDetails.modulus;
exponent = publicKeyDetails.exponent;
startIndex = findStartIndex(publicKeyDetails.modulus, dsc_message_padded).toString();
const modulus = (publicKeyDetails as PublicKeyDetailsRSA).modulus;
exponent = (publicKeyDetails as PublicKeyDetailsRSA).exponent;
startIndex = findStartIndex(
(publicKeyDetails as PublicKeyDetailsRSA).modulus,
dsc_message_padded
).toString();
dsc_message_padded_formatted = Array.from(dsc_message_padded).map((x) => x.toString());
dsc_messagePaddedLen_formatted = BigInt(dsc_messagePaddedLen).toString();
console.log("\x1b[34m", "startIndex: ", startIndex, "\x1b[0m");
console.log('\x1b[34m', 'startIndex: ', startIndex, '\x1b[0m');
pubKey_dsc = formatInput(splitToWords(BigInt(hexToDecimal(modulus)), n, k));
}
else {
console.log("\x1b[34m", "signatureAlgorithm: ", signatureAlgorithm, "\x1b[0m");
} else {
console.log('\x1b[34m', 'signatureAlgorithm: ', signatureAlgorithm, '\x1b[0m');
// TODO: implement ecdsa
// const { r, s } = extractRSFromSignature(encryptedDigest);
// const signature_r = splitToWords(BigInt(hexToDecimal(r)), n_csca, k_csca);
@@ -117,7 +112,6 @@ export function generateCircuitInputsDSC(
const leaf = getLeafCSCA(cscaPem);
const [root, proof] = getCSCAModulusProof(leaf);
const parsedCSCAPem: CertificateData = parseCertificateSimple(cscaPem);
let csca_pubKey_formatted;
@@ -129,18 +123,15 @@ export function generateCircuitInputsDSC(
char.charCodeAt(0)
);
signature = formatInput(splitToWords(BigInt(bytesToBigDecimal(signature_raw)), n_csca, k_csca));
} else {
// const csca_x_formatted = splitToWords(BigInt(hexToDecimal(csca_x)), n_csca, k_csca);
// const csca_y_formatted = splitToWords(BigInt(hexToDecimal(csca_y)), n_csca, k_csca);
// csca_pubKey_formatted = [...csca_x_formatted, ...csca_y_formatted];
}
const dummy = 0;
console.log('dsc_pubKey_length', pubKey_dsc.length);
return {
signature_algorithm: `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${4096}`,
signature_algorithm: `${signatureAlgorithm}_${curve || exponent}_${hashAlgorithm}_${4096}`,
inputs: {
raw_dsc_cert: dsc_message_padded_formatted,
raw_dsc_cert_padded_bytes: [dsc_messagePaddedLen_formatted],
@@ -151,7 +142,7 @@ export function generateCircuitInputsDSC(
secret: [dscSecret],
merkle_root: [BigInt(root).toString()],
path: proof.pathIndices.map((index) => index.toString()),
siblings: proof.siblings.flat().map((sibling) => sibling.toString())
siblings: proof.siblings.flat().map((sibling) => sibling.toString()),
},
};
}

View File

@@ -0,0 +1,85 @@
import elliptic from 'elliptic';
import hash from 'hash.js';
export function initElliptic(): typeof elliptic {
const curves = elliptic.curves;
const PresetCurve = elliptic.curves.PresetCurve;
function defineCurve(name: string, options: any) {
Object.defineProperty(curves, name, {
configurable: true,
enumerable: true,
get: function () {
var curve = new PresetCurve(options);
Object.defineProperty(curves, name, {
configurable: true,
enumerable: true,
value: curve,
});
return curve;
},
});
}
defineCurve('brainpoolP224r1', {
type: 'short',
prime: null,
p: 'd7c134aa 26436686 2a183025 75d1d787 b09f0757 97da89f5 7ec8c0ff',
a: '68a5e62c a9ce6c1c 299803a6 c1530b51 4e182ad8 b0042a59 cad29f43',
b: '2580f63c cfe44138 870713b1 a92369e3 3e2135d2 66dbb372 386c400b',
n: 'd7c134aa 26436686 2a183025 75d0fb98 d116bc4b 6ddebca3 a5a7939f',
hash: hash.sha1,
gRed: false,
g: [
'0d9029ad 2c7e5cf4 340823b2 a87dc68c 9e4ce317 4c1e6efd ee12c07d',
'58aa56f7 72c0726f 24c6b89e 4ecdac24 354b9e99 caa3f6d3 761402cd',
],
});
defineCurve('brainpoolP256r1', {
type: 'short',
prime: null,
p: 'a9fb57db a1eea9bc 3e660a90 9d838d72 6e3bf623 d5262028 2013481d 1f6e5377',
a: '7d5a0975 fc2c3057 eef67530 417affe7 fb8055c1 26dc5c6c e94a4b44 f330b5d9',
b: '26dc5c6c e94a4b44 f330b5d9 bbd77cbf 95841629 5cf7e1ce 6bccdc18 ff8c07b6',
n: 'a9fb57db a1eea9bc 3e660a90 9d838d71 8c397aa3 b561a6f7 901e0e82 974856a7',
hash: hash.sha256,
gRed: false,
g: [
'8bd2aeb9 cb7e57cb 2c4b482f fc81b7af b9de27e1 e3bd23c2 3a4453bd 9ace3262',
'547ef835 c3dac4fd 97f8461a 14611dc9 c2774513 2ded8e54 5c1d54c7 2f046997',
],
});
defineCurve('brainpoolP384r1', {
type: 'short',
prime: null,
p: '8cb91e82 a3386d28 0f5d6f7e 50e641df 152f7109 ed5456b4 12b1da19 7fb71123 acd3a729 901d1a71 87470013 3107ec53',
a: '7bc382c6 3d8c150c 3c72080a ce05afa0 c2bea28e 4fb22787 139165ef ba91f90f 8aa5814a 503ad4eb 04a8c7dd 22ce2826',
b: '04a8c7dd 22ce2826 8b39b554 16f0447c 2fb77de1 07dcd2a6 2e880ea5 3eeb62d5 7cb43902 95dbc994 3ab78696 fa504c11',
n: '8cb91e82 a3386d28 0f5d6f7e 50e641df 152f7109 ed5456b3 1f166e6c ac0425a7 cf3ab6af 6b7fc310 3b883202 e9046565',
hash: hash.sha384,
gRed: false,
g: [
'1d1c64f0 68cf45ff a2a63a81 b7c13f6b 8847a3e7 7ef14fe3 db7fcafe 0cbd10e8 e826e034 36d646aa ef87b2e2 47d4af1e',
'8abe1d75 20f9c2a4 5cb1eb8e 95cfd552 62b70b29 feec5864 e19c054f f9912928 0e464621 77918111 42820341 263c5315',
],
});
defineCurve('brainpoolP512r1', {
type: 'short',
prime: null,
p: 'aadd9db8 dbe9c48b 3fd4e6ae 33c9fc07 cb308db3 b3c9d20e d6639cca 70330871 7d4d9b00 9bc66842 aecda12a e6a380e6 2881ff2f 2d82c685 28aa6056 583a48f3',
a: '7830a331 8b603b89 e2327145 ac234cc5 94cbdd8d 3df91610 a83441ca ea9863bc 2ded5d5a a8253aa1 0a2ef1c9 8b9ac8b5 7f1117a7 2bf2c7b9 e7c1ac4d 77fc94ca',
b: '3df91610 a83441ca ea9863bc 2ded5d5a a8253aa1 0a2ef1c9 8b9ac8b5 7f1117a7 2bf2c7b9 e7c1ac4d 77fc94ca dc083e67 984050b7 5ebae5dd 2809bd63 8016f723',
n: 'aadd9db8 dbe9c48b 3fd4e6ae 33c9fc07 cb308db3 b3c9d20e d6639cca 70330870 553e5c41 4ca92619 41866119 7fac1047 1db1d381 085ddadd b5879682 9ca90069',
hash: hash.sha512,
gRed: false,
g: [
'81aee4bd d82ed964 5a21322e 9c4c6a93 85ed9f70 b5d916c1 b43b62ee f4d0098e ff3b1f78 e2d0d48d 50d1687b 93b97d5f 7c6d5047 406a5e68 8b352209 bcb9f822',
'7dde385d 566332ec c0eabfa9 cf7822fd f209f700 24a57b1a a000c55b 881f8111 b2dcde49 4a5f485e 5bca4bd8 8a2763ae d1ca2b2f a8f05406 78cd1e0f 3ad80892',
],
});
return elliptic;
}

View File

@@ -1,5 +1,11 @@
import { PassportData } from './types';
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz } from './utils';
import {
hash,
generateSignedAttr,
formatAndConcatenateDataHashes,
formatMrz,
getHashLen,
} from './utils';
import * as forge from 'node-forge';
import * as asn1 from 'asn1js';
import elliptic from 'elliptic';
@@ -51,13 +57,37 @@ import {
mock_dsc_key_sha512_brainpoolP512r1,
mock_dsc_sha512_brainpoolP512r1,
} from '../constants/mockCertificates';
import { sampleDataHashes_small, sampleDataHashes_large } from '../constants/sampleDataHashes';
import { countryCodes } from '../constants/constants';
import { parseCertificate } from './certificates/handleCertificate';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import { SignatureAlgorithm } from './types';
import { randomBytes } from 'crypto';
import { getCurveForElliptic } from './certificates/curves';
import { PublicKeyDetailsECDSA, PublicKeyDetailsRSAPSS } from './certificate_parsing/dataStructure';
import { getCurveForElliptic } from './certificate_parsing/curves';
function generateRandomBytes(length: number): number[] {
// Generate numbers between -128 and 127 to match the existing signed byte format
return Array.from({ length }, () => Math.floor(Math.random() * 256) - 128);
}
function generateDataGroupHashes(mrzHash: number[], hashLen: number): [number, number[]][] {
// Generate hashes for DGs 2-15 (excluding some DGs that aren't typically used)
const dataGroups: [number, number[]][] = [
[1, mrzHash], // DG1 must be the MRZ hash
[2, generateRandomBytes(hashLen)],
[3, generateRandomBytes(hashLen)],
[4, generateRandomBytes(hashLen)],
[5, generateRandomBytes(hashLen)],
[7, generateRandomBytes(hashLen)],
[11, generateRandomBytes(hashLen)],
[12, generateRandomBytes(hashLen)],
[14, generateRandomBytes(hashLen)],
];
return dataGroups;
}
export function genMockPassportData(
dgHashAlgo: string,
eContentHashAlgo: string,
signatureType: SignatureAlgorithm,
nationality: keyof typeof countryCodes,
birthDate: string,
@@ -107,157 +137,130 @@ export function genMockPassportData(
let privateKeyPem: string;
let dsc: string;
let sampleDataHashes: [number, number[]][];
switch (signatureType) {
case 'rsa_sha1_65537_2048':
sampleDataHashes = genSampleDataHashes('small', 20);
privateKeyPem = mock_dsc_key_sha1_rsa_4096;
dsc = mock_dsc_sha1_rsa_4096;
break;
case 'rsa_sha256_65537_2048':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_rsa_4096;
dsc = mock_dsc_sha256_rsa_4096;
break;
case 'rsapss_sha256_65537_2048':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_rsapss_4096;
dsc = mock_dsc_sha256_rsapss_4096;
break;
case 'rsapss_sha256_3_4096':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_rsapss_3_4096;
dsc = mock_dsc_sha256_rsapss_3_4096;
break;
case 'rsapss_sha256_3_3072':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_rsapss_3_3072;
dsc = mock_dsc_sha256_rsapss_3_3072;
break;
case 'rsapss_sha384_65537_3072':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha384_rsapss_65537_3072;
dsc = mock_dsc_sha384_rsapss_65537_3072;
break;
case 'ecdsa_sha256_secp256r1_256':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_ecdsa;
dsc = mock_dsc_sha256_ecdsa;
break;
case 'ecdsa_sha1_secp256r1_256':
sampleDataHashes = genSampleDataHashes('small', 20);
privateKeyPem = mock_dsc_key_sha1_ecdsa;
dsc = mock_dsc_sha1_ecdsa;
break;
case 'ecdsa_sha384_secp384r1_384':
sampleDataHashes = genSampleDataHashes('large', 48);
privateKeyPem = mock_dsc_key_sha384_ecdsa;
dsc = mock_dsc_sha384_ecdsa;
break;
case 'ecdsa_sha256_secp384r1_384':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_secp384r1;
dsc = mock_dsc_sha256_secp384r1;
break;
case 'ecdsa_sha256_brainpoolP256r1_256':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_brainpoolP256r1;
dsc = mock_dsc_sha256_brainpoolP256r1;
break;
case 'ecdsa_sha384_brainpoolP256r1_256':
sampleDataHashes = genSampleDataHashes('large', 48);
privateKeyPem = mock_dsc_key_sha384_brainpoolP256r1;
dsc = mock_dsc_sha384_brainpoolP256r1;
break;
case 'ecdsa_sha512_brainpoolP256r1_256':
sampleDataHashes = genSampleDataHashes('large', 64);
privateKeyPem = mock_dsc_key_sha512_brainpoolP256r1;
dsc = mock_dsc_sha512_brainpoolP256r1;
break;
case 'rsa_sha256_3_2048':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_rsa_3_2048;
dsc = mock_dsc_sha256_rsa_3_2048;
break;
case 'rsa_sha256_65537_3072':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_rsa_65537_3072;
dsc = mock_dsc_sha256_rsa_65537_3072;
break;
case 'rsapss_sha256_65537_3072':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_rsapss_65537_3072;
dsc = mock_dsc_sha256_rsapss_65537_3072;
break;
case 'rsapss_sha256_65537_4096':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_rsapss_65537_4096;
dsc = mock_dsc_sha256_rsapss_65537_4096;
break;
case 'ecdsa_sha384_brainpoolP384r1_384':
sampleDataHashes = genSampleDataHashes('large', 48);
privateKeyPem = mock_dsc_key_sha384_brainpoolP384r1;
dsc = mock_dsc_sha384_brainpoolP384r1;
break;
case 'ecdsa_sha512_brainpoolP384r1_384':
sampleDataHashes = genSampleDataHashes('large', 64);
privateKeyPem = mock_dsc_key_sha512_brainpoolP384r1;
dsc = mock_dsc_sha512_brainpoolP384r1;
break;
case 'ecdsa_sha1_brainpoolP224r1_224':
sampleDataHashes = genSampleDataHashes('large', 20);
privateKeyPem = mock_dsc_key_sha1_brainpoolP224r1;
dsc = mock_dsc_sha1_brainpoolP224r1;
break;
case 'ecdsa_sha256_brainpoolP224r1_224':
sampleDataHashes = genSampleDataHashes('large', 32);
privateKeyPem = mock_dsc_key_sha256_brainpoolP224r1;
dsc = mock_dsc_sha256_brainpoolP224r1;
break;
case 'ecdsa_sha512_brainpoolP512r1_512':
sampleDataHashes = genSampleDataHashes('large', 64);
privateKeyPem = mock_dsc_key_sha512_brainpoolP512r1;
dsc = mock_dsc_sha512_brainpoolP512r1;
break;
}
const { hashFunction, hashLen } = parseCertificate(dsc);
// Generate MRZ hash first
const mrzHash = hash(dgHashAlgo, formatMrz(mrz));
const mrzHash = hash(hashFunction, formatMrz(mrz));
const concatenatedDataHashes = formatAndConcatenateDataHashes(
[[1, mrzHash], ...sampleDataHashes],
hashLen,
30
);
// Generate random hashes for other DGs, passing mrzHash for DG1
const dataGroupHashes = generateDataGroupHashes(mrzHash, getHashLen(dgHashAlgo));
const eContent = assembleEContent(hash(hashFunction, concatenatedDataHashes));
const eContent = formatAndConcatenateDataHashes(dataGroupHashes, 63);
const signature = sign(privateKeyPem, dsc, eContent);
const signedAttr = generateSignedAttr(hash(eContentHashAlgo, eContent));
const hashAlgo = signatureType.split('_')[1];
const signature = sign(privateKeyPem, dsc, hashAlgo, signedAttr);
const signatureBytes = Array.from(signature, (byte) => (byte < 128 ? byte : byte - 256));
return {
dsc: dsc,
mrz: mrz,
dg2Hash: sampleDataHashes[0][1],
eContent: concatenatedDataHashes,
signedAttr: eContent,
dg2Hash: dataGroupHashes.find(([dgNum]) => dgNum === 2)?.[1] || [],
eContent: eContent,
signedAttr: signedAttr,
encryptedDigest: signatureBytes,
photoBase64: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIy3...',
mockUser: true,
};
}
const genSampleDataHashes = (
type: 'small' | 'large',
bytes: 20 | 32 | 48 | 64
): [number, number[]][] => {
const groups = type === 'small' ? [2, 3, 14] : [2, 3, 11, 12, 13, 14];
return groups.map((group) => [group, Array.from(randomBytes(bytes))]);
};
function sign(privateKeyPem: string, dsc: string, eContent: number[]): number[] {
const { signatureAlgorithm, hashFunction, curve } = parseCertificate(dsc);
function sign(
privateKeyPem: string,
dsc: string,
hashAlgorithm: string,
eContent: number[]
): number[] {
const { signatureAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc);
if (signatureAlgorithm === 'rsapss') {
const privateKey = forge.pki.privateKeyFromPem(privateKeyPem);
@@ -266,11 +269,12 @@ function sign(privateKeyPem: string, dsc: string, eContent: number[]): number[]
const pss = forge.pss.create({
md: forge.md.sha256.create(),
mgf: forge.mgf.mgf1.create(forge.md.sha256.create()),
saltLength: 32,
saltLength: parseInt((publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength),
});
const signatureBytes = privateKey.sign(md, pss);
return Array.from(signatureBytes, (c: string) => c.charCodeAt(0));
} else if (signatureAlgorithm === 'ecdsa') {
const curve = (publicKeyDetails as PublicKeyDetailsECDSA).curve;
let curveForElliptic = getCurveForElliptic(curve);
const ec = new elliptic.ec(curveForElliptic);
@@ -280,18 +284,26 @@ function sign(privateKeyPem: string, dsc: string, eContent: number[]): number[]
);
const asn1Data = asn1.fromBER(privateKeyDer);
const privateKeyBuffer = (asn1Data.result.valueBlock as any).value[1].valueBlock.valueHexView;
// console.log('sig deets');
// console.log('pk', privateKeyBuffer);
// console.log('hashFUnction', hashAlgorithm);
// console.log('message', Buffer.from(eContent).toString('hex'));
const keyPair = ec.keyFromPrivate(privateKeyBuffer);
let md = forge.md[hashFunction].create();
let md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
// console.log('message to sign', md.digest().toHex());
const signature = keyPair.sign(md.digest().toHex(), 'hex');
// console.log(Buffer.from(signature.toDER(), 'hex').toString('hex'));
const signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex'));
// console.log('sig', JSON.stringify(signatureBytes));
return signatureBytes;
} else {
const privKey = forge.pki.privateKeyFromPem(privateKeyPem);
const md = hashFunction === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create();
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
const forgeSignature = privKey.sign(md);
return Array.from(forgeSignature, (c: string) => c.charCodeAt(0));

View File

@@ -30,7 +30,9 @@ import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
import { getCountryLeaf, getNameLeaf, getNameDobLeaf, getPassportNumberLeaf } from './smtTree';
import { packBytes } from '../utils/utils';
import { SMT } from '@openpassport/zk-kit-smt';
import { parseCertificate } from './certificates/handleCertificate';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import { PublicKeyDetailsECDSA, PublicKeyDetailsRSA } from './certificate_parsing/dataStructure';
import { parsePassportData } from './parsePassportData';
export function generateCircuitInputsDisclose(
secret: string,
@@ -181,18 +183,18 @@ export function generateCircuitInputsProve(
user_identifier_type: 'uuid' | 'hex' | 'ascii' = DEFAULT_USER_ID_TYPE
) {
const { mrz, eContent, signedAttr, encryptedDigest, dsc, dg2Hash } = passportData;
const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } =
parseCertificate(passportData.dsc);
const signatureAlgorithmFullName = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`;
const passportMetadata = parsePassportData(passportData);
const hashAlgorithm = passportMetadata.signedAttrHashFunction;
const { signatureAlgorithm, publicKeyDetails } = parseCertificateSimple(passportData.dsc);
let pubKey: any;
let signature: any;
const { n, k } = getNAndK(
`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}` as SignatureAlgorithm
);
let signatureAlgorithmFullName: string;
let n, k;
if (signatureAlgorithm === 'ecdsa') {
signatureAlgorithmFullName = `${signatureAlgorithm}_${hashAlgorithm}_${(publicKeyDetails as PublicKeyDetailsECDSA).curve}_${publicKeyDetails.bits}`;
({ n, k } = getNAndK(signatureAlgorithmFullName as SignatureAlgorithm));
const { x, y } = publicKeyDetails as PublicKeyDetailsECDSA;
const { r, s } = extractRSFromSignature(encryptedDigest);
const signature_r = splitToWords(BigInt(hexToDecimal(r)), n, k);
const signature_s = splitToWords(BigInt(hexToDecimal(s)), n, k);
@@ -201,45 +203,40 @@ export function generateCircuitInputsProve(
const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n, k);
pubKey = [...dsc_modulus_x, ...dsc_modulus_y];
} else {
const { modulus, exponent } = publicKeyDetails as PublicKeyDetailsRSA;
signatureAlgorithmFullName = `${signatureAlgorithm}_${hashAlgorithm}_${exponent}_${publicKeyDetails.bits}`;
({ n, k } = getNAndK(signatureAlgorithmFullName as SignatureAlgorithm));
signature = splitToWords(BigInt(bytesToBigDecimal(encryptedDigest)), n, k);
pubKey = splitToWords(BigInt(hexToDecimal(modulus)), n, k);
}
const formattedMrz = formatMrz(mrz);
const dg1Hash = hash(hashFunction, formattedMrz);
const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash);
console.log('\x1b[90m%s\x1b[0m', 'dg1HashOffset', dg1HashOffset);
assert(dg1HashOffset !== -1, `DG1 hash ${dg1Hash} not found in eContent`);
console.log(
JSON.stringify(eContent.slice(dg1HashOffset, dg1HashOffset + 512 / 8).map((x) => x & 0xff))
);
const eContentHash = hash(hashFunction, eContent);
const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash);
console.log('\x1b[90m%s\x1b[0m', 'eContentHashOffset', eContentHashOffset);
assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`);
if (eContent.length > MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]) {
console.error(
`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]} bytes.`
`eContent too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]} bytes.`
);
throw new Error(
`This length of datagroups (${eContent.length} bytes) is currently unsupported. Please contact us so we add support!`
);
}
const paddingFunction =
hashFunction == 'sha1' || hashFunction == 'sha256' ? shaPad : sha384_512Pad;
// const paddingFunction =
// hashFunction == 'sha1' || hashFunction == 'sha256' ? shaPad : sha384_512Pad;
const [eContentPadded, eContentLen] = paddingFunction(
const dg1PaddingFunction =
MAX_PADDED_ECONTENT_LEN[passportMetadata.dg1HashFunction] <= 256 ? shaPad : sha384_512Pad;
const [eContentPadded, eContentLen] = dg1PaddingFunction(
new Uint8Array(eContent),
MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]
MAX_PADDED_ECONTENT_LEN[passportMetadata.dg1HashFunction]
);
const [signedAttrPadded, signedAttrPaddedLen] = paddingFunction(
const eContentPaddingFunction =
MAX_PADDED_ECONTENT_LEN[passportMetadata.eContentHashFunction] <= 256 ? shaPad : sha384_512Pad;
const [signedAttrPadded, signedAttrPaddedLen] = eContentPaddingFunction(
new Uint8Array(signedAttr),
MAX_PADDED_SIGNED_ATTR_LEN[signatureAlgorithmFullName]
MAX_PADDED_SIGNED_ATTR_LEN[passportMetadata.eContentHashFunction]
);
const formattedMajority = majority.length === 1 ? `0${majority}` : majority;
@@ -257,13 +254,13 @@ export function generateCircuitInputsProve(
return {
selector_mode: formatInput(selector_mode),
dg1: formatInput(formattedMrz),
dg1_hash_offset: formatInput(dg1HashOffset),
dg1_hash_offset: formatInput(passportMetadata.dg1HashOffset),
dg2_hash: formatInput(formatDg2Hash(dg2Hash)),
eContent: Array.from(eContentPadded).map((x) => x.toString()),
eContent_padded_length: formatInput(eContentLen),
signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()),
signed_attr_padded_length: formatInput(signedAttrPaddedLen),
signed_attr_econtent_hash_offset: formatInput(eContentHashOffset),
signed_attr_econtent_hash_offset: formatInput(passportMetadata.eContentHashOffset),
signature: signature,
pubKey: pubKey,
current_date: formatInput(getCurrentDateYYMMDD()),

View File

@@ -1,5 +1,4 @@
import { ECDSA_K_LENGTH_FACTOR, k_dsc, k_dsc_ecdsa } from '../constants/constants';
import { parseDSC } from './certificates/handleCertificate';
import {
bigIntToHex,
castToScope,

View File

@@ -0,0 +1,239 @@
import { PassportData } from '../../../common/src/utils/types';
import { findSubarrayIndex, formatMrz, hash } from './utils';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import {
CertificateData,
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
} from './certificate_parsing/dataStructure';
import { getCSCAFromSKI } from './csca';
import { hashAlgos } from '../constants/constants';
import { Certificate } from 'pkijs';
import forge from 'node-forge';
import * as asn1js from 'asn1js';
import { initElliptic } from './elliptic';
import { getCurveForElliptic } from './certificate_parsing/curves';
export interface PassportMetadata {
dataGroups: string;
dg1HashFunction: string;
dg1HashOffset: number;
eContentSize: number;
eContentHashFunction: string;
eContentHashOffset: number;
signedAttrSize: number;
signedAttrHashFunction: string;
signatureAlgorithm: string;
signatureAlgorithmDetails: string;
curveOrExponent: string;
signatureAlgorithmBits: number;
countryCode: string;
cscaFound: boolean;
cscaHashFunction: string;
cscaSignature: string;
cscaSignatureAlgorithmDetails: string;
cscaCurveOrExponent: string;
cscaSignatureAlgorithmBits: number;
dsc: string;
}
export function findHashSizeOfEContent(eContent: number[], signedAttr: number[]) {
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, eContent);
const hashOffset = findSubarrayIndex(signedAttr, hashValue);
if (hashOffset !== -1) {
return { hashFunction, offset: hashOffset };
}
}
return { hashFunction: 'unknown', offset: -1 };
}
export function findDG1HashInEContent(
mrz: string,
eContent: number[]
): { hash: number[]; hashFunction: string; offset: number } | null {
const formattedMrz = formatMrz(mrz);
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, formattedMrz);
const normalizedHash = hashValue.map((byte) => (byte > 127 ? byte - 256 : byte));
const hashOffset = findSubarrayIndex(eContent, normalizedHash);
if (hashOffset !== -1) {
return { hash: hashValue, hashFunction, offset: hashOffset };
}
}
return null;
}
export function getCountryCodeFromMrz(mrz: string): string {
return mrz.substring(2, 5);
}
export function getCurveOrExponent(certData: CertificateData): string {
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
return (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
}
return (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
export function getSimplePublicKeyDetails(certData: CertificateData): string {
interface SimplePublicKeyDetails {
exponent?: string;
curve?: string;
hashAlgorithm?: string;
saltLength?: string;
}
const simplePublicKeyDetails: SimplePublicKeyDetails = {};
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
simplePublicKeyDetails.exponent = (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
if (certData.signatureAlgorithm === 'rsapss') {
simplePublicKeyDetails.hashAlgorithm = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).hashAlgorithm;
simplePublicKeyDetails.saltLength = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).saltLength;
}
} else if (certData.signatureAlgorithm === 'ecdsa') {
simplePublicKeyDetails.curve = (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
return JSON.stringify(simplePublicKeyDetails);
}
export function verifySignature(passportData: PassportData, hashAlgorithm: string): boolean {
const elliptic = initElliptic();
const { dsc, signedAttr, encryptedDigest } = passportData;
const { signatureAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc);
if (signatureAlgorithm === 'ecdsa') {
const certBuffer = Buffer.from(
dsc.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1js.fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data.result });
const publicKeyInfo = cert.subjectPublicKeyInfo;
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = getCurveForElliptic((publicKeyDetails as PublicKeyDetailsECDSA).curve);
const ec = new elliptic.ec(curveForElliptic);
const key = ec.keyFromPublic(publicKeyBuffer);
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const msgHash = md.digest().toHex();
const signature_crypto = Buffer.from(encryptedDigest).toString('hex');
return key.verify(msgHash, signature_crypto);
} else {
const cert = forge.pki.certificateFromPem(dsc);
const publicKey = cert.publicKey as forge.pki.rsa.PublicKey;
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const signature = Buffer.from(encryptedDigest).toString('binary');
if (signatureAlgorithm === 'rsapss') {
try {
const pss = forge.pss.create({
md: forge.md[hashAlgorithm].create(),
mgf: forge.mgf.mgf1.create(forge.md[hashAlgorithm].create()),
saltLength: parseInt((publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength),
});
return publicKey.verify(md.digest().bytes(), signature, pss);
} catch (error) {
return false;
}
} else {
return publicKey.verify(md.digest().bytes(), signature);
}
}
}
export function brutforceHashAlgorithm(passportData: PassportData): any {
for (const hashFunction of hashAlgos) {
if (verifySignature(passportData, hashFunction)) {
return hashFunction;
}
}
return null;
}
export function parsePassportData(passportData: PassportData): PassportMetadata {
const dg1HashInfo = passportData.mrz
? findDG1HashInEContent(passportData.mrz, passportData.eContent)
: null;
const dg1HashFunction = dg1HashInfo?.hashFunction || 'unknown';
const dg1HashOffset = dg1HashInfo?.offset || 0;
const { hashFunction: eContentHashFunction, offset: eContentHashOffset } = findHashSizeOfEContent(
passportData.eContent,
passportData.signedAttr
);
const signatureHashAlgo = brutforceHashAlgorithm(passportData);
let parsedDsc = null;
let parsedCsca = null;
let csca = null;
let dscSignature = 'unknown';
let dscSignatureAlgorithmDetails = 'unknown';
let dscSignatureAlgorithmBits = 0;
let cscaHashFunction = 'unknown';
let cscaSignature = 'unknown';
let cscaSignatureAlgorithmDetails = 'unknown';
let cscaSignatureAlgorithmBits = 0;
if (passportData.dsc) {
parsedDsc = parseCertificateSimple(passportData.dsc);
dscSignature = parsedDsc.signatureAlgorithm;
dscSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedDsc);
dscSignatureAlgorithmBits = parseInt(parsedDsc.publicKeyDetails?.bits || '0');
if (parsedDsc.authorityKeyIdentifier) {
try {
csca = getCSCAFromSKI(parsedDsc.authorityKeyIdentifier, true);
if (csca) {
parsedCsca = parseCertificateSimple(csca);
cscaHashFunction = parsedCsca.hashAlgorithm;
cscaSignature = parsedCsca.signatureAlgorithm;
cscaSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedCsca);
cscaSignatureAlgorithmBits = parseInt(parsedCsca.publicKeyDetails?.bits || '0');
}
} catch (error) {
console.error('Error getting CSCA from SKI', error);
}
}
}
return {
dataGroups:
passportData.dgPresents
?.toString()
.split(',')
.map((item) => item.replace('DG', ''))
.join(',') || 'None',
dg1HashFunction,
dg1HashOffset,
eContentSize: passportData.eContent?.length || 0,
eContentHashFunction,
eContentHashOffset,
signedAttrSize: passportData.signedAttr?.length || 0,
signedAttrHashFunction: signatureHashAlgo,
signatureAlgorithm: dscSignature,
signatureAlgorithmDetails: dscSignatureAlgorithmDetails,
curveOrExponent: parsedDsc ? getCurveOrExponent(parsedDsc) : 'unknown',
signatureAlgorithmBits: dscSignatureAlgorithmBits,
countryCode: passportData.mrz ? getCountryCodeFromMrz(passportData.mrz) : 'unknown',
cscaFound: !!csca,
cscaHashFunction,
cscaSignature,
cscaSignatureAlgorithmDetails,
cscaCurveOrExponent: parsedCsca ? getCurveOrExponent(parsedCsca) : 'unknown',
cscaSignatureAlgorithmBits: cscaSignatureAlgorithmBits,
dsc: passportData.dsc,
};
}

View File

@@ -1,14 +1,15 @@
import {
PUBKEY_TREE_DEPTH,
COMMITMENT_TREE_TRACKER_URL,
SignatureAlgorithmIndex,
} from '../constants/constants';
import { SignatureAlgorithmIndex } from '../constants/constants';
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
import axios from 'axios';
import { poseidon16, poseidon2, poseidon6, poseidon7 } from 'poseidon-lite';
import { poseidon16, poseidon2, poseidon7 } from 'poseidon-lite';
import { formatDg2Hash, getNAndK, getNAndKCSCA, hexToDecimal, splitToWords } from './utils';
import { parseCertificate } from './certificates/handleCertificate';
import { flexiblePoseidon } from './poseidon';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import {
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
} from './certificate_parsing/dataStructure';
import { SignatureAlgorithm } from './types';
export function customHasher(pubKeyFormatted: string[]) {
const rounds = Math.ceil(pubKeyFormatted.length / 16);
@@ -28,44 +29,66 @@ export function customHasher(pubKeyFormatted: string[]) {
}
export function getLeaf(dsc: string): string {
const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } =
parseCertificate(dsc);
const { n, k } = getNAndK(signatureAlgorithm);
const sigAlgKey = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`;
const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey];
const { signatureAlgorithm, publicKeyDetails, hashAlgorithm } = parseCertificateSimple(dsc);
if (sigAlgIndex == undefined) {
console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`);
throw new Error(`Invalid signature algorithm: ${sigAlgKey}`);
}
if (signatureAlgorithm === 'ecdsa') {
const { x, y, curve, bits } = publicKeyDetails as PublicKeyDetailsECDSA;
const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${curve}_${bits}`;
const { n, k } = getNAndK(sigAlgKey as SignatureAlgorithm);
const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey];
if (sigAlgIndex == undefined) {
console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`);
throw new Error(`Invalid signature algorithm: ${sigAlgKey}`);
}
let qx = splitToWords(BigInt(hexToDecimal(x)), n, k);
let qy = splitToWords(BigInt(hexToDecimal(y)), n, k);
return customHasher([sigAlgIndex, ...qx, ...qy]);
} else {
const { modulus, bits, exponent } = publicKeyDetails as PublicKeyDetailsRSA;
const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${exponent}_${bits}`;
const { n, k } = getNAndK(sigAlgKey as SignatureAlgorithm);
const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k);
const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey];
if (sigAlgIndex == undefined) {
console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`);
throw new Error(`Invalid signature algorithm: ${sigAlgKey}`);
}
return customHasher([sigAlgIndex, ...pubkeyChunked]);
}
}
export function getLeafCSCA(dsc: string): string {
const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } =
parseCertificate(dsc);
const { n, k } = getNAndKCSCA(signatureAlgorithm);
console.log(`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`);
const sigAlgKey = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`;
console.log('sigAlgKey', sigAlgKey);
const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey];
console.log('sigAlgIndex', sigAlgIndex);
const { signatureAlgorithm, publicKeyDetails, hashAlgorithm } = parseCertificateSimple(dsc);
const { n, k } = getNAndKCSCA(signatureAlgorithm as any);
if (sigAlgIndex == undefined) {
console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`);
throw new Error(`Invalid signature algorithm: ${sigAlgKey}`);
}
if (signatureAlgorithm === 'ecdsa') {
const { x, y, curve, bits } = publicKeyDetails as PublicKeyDetailsECDSA;
const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${curve}_${bits}`;
const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey];
let qx = splitToWords(BigInt(hexToDecimal(x)), n, k);
let qy = splitToWords(BigInt(hexToDecimal(y)), n, k);
return customHasher([sigAlgIndex, ...qx, ...qy]);
} else {
} else if (signatureAlgorithm === 'rsa') {
const { modulus, bits, exponent } = publicKeyDetails as PublicKeyDetailsRSA;
const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${exponent}_${bits}`;
const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey];
const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k);
return customHasher([sigAlgIndex, ...pubkeyChunked]);
if (sigAlgIndex == undefined) {
console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`);
throw new Error(`Invalid signature algorithm: ${sigAlgKey}`);
}
} else if (signatureAlgorithm === 'rsapss') {
const { modulus, bits, exponent, hashAlgorithm } = publicKeyDetails as PublicKeyDetailsRSAPSS;
const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${exponent}_${bits}`;
const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey];
if (sigAlgIndex == undefined) {
console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`);
throw new Error(`Invalid signature algorithm: ${sigAlgKey}`);
}
const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k);
return customHasher([sigAlgIndex, ...pubkeyChunked]);
}

View File

@@ -24,20 +24,20 @@ export type SignatureAlgorithm =
| 'ecdsa_sha1_secp256r1_256'
| 'ecdsa_sha384_secp384r1_384'
| 'ecdsa_sha256_secp384r1_384'
| 'ecdsa_sha256_brainpoolP256r1_256'
| 'ecdsa_sha384_brainpoolP256r1_256'
| 'ecdsa_sha512_brainpoolP256r1_256'
| 'ecdsa_sha256_brainpoolP256r1_256'
| 'rsa_sha256_3_2048'
| 'rsa_sha256_65537_3072'
| 'rsa_sha256_65537_4096'
| 'rsa_sha512_65537_4096'
| 'rsapss_sha256_65537_3072'
| 'rsapss_sha256_65537_4096'
| 'ecdsa_sha384_brainpoolP384r1_384'
| 'ecdsa_sha512_brainpoolP384r1_384'
| 'ecdsa_sha1_brainpoolP224r1_224'
| 'ecdsa_sha256_brainpoolP224r1_224'
| 'ecdsa_sha512_brainpoolP512r1_512';
| 'ecdsa_sha512_brainpoolP512r1_512'
| 'rsapss_sha256_65537_4096';
export type Proof = {
proof: {

View File

@@ -89,7 +89,6 @@ export function formatDg2Hash(dg2Hash: number[]) {
export function formatAndConcatenateDataHashes(
dataHashes: [number, number[]][],
hashLen: number,
dg1HashOffset: number
) {
// concatenating dataHashes :
@@ -171,7 +170,7 @@ export function formatAndConcatenateDataHashes(
return concat;
}
export function assembleEContent(messageDigest: number[]) {
export function generateSignedAttr(messageDigest: number[]) {
const constructedEContent = [];
// Detailed description is in private file r&d.ts for now
@@ -421,8 +420,21 @@ export function generateMerkleProof(imt: LeanIMT, _index: number, maxDepth: numb
return { merkleProofSiblings, merkleProofIndices, depthForThisOne };
}
export function findSubarrayIndex(arr: any[], subarray: any[]): number {
return arr.findIndex((_, index) => subarray.every((element, i) => element === arr[index + i]));
export function findSubarrayIndex(arr: number[], subArr: number[]): number {
if (!arr || !Array.isArray(arr) || !subArr || !Array.isArray(subArr)) {
console.warn('Invalid input to findSubarrayIndex:', { arr, subArr });
return -1;
}
if (subArr.length === 0) {
return -1;
}
if (subArr.length > arr.length) {
return -1;
}
return arr.findIndex((_, i) => subArr.every((val, j) => arr[i + j] === val));
}
export function extractRSFromSignature(signatureBytes: number[]): { r: string; s: string } {

View File

@@ -1,97 +1,42 @@
import { assert, expect } from 'chai';
import { describe, it } from 'mocha';
import { genMockPassportData } from '../src/utils/genMockPassportData';
import * as forge from 'node-forge';
import { PassportData, SignatureAlgorithm } from '../src/utils/types';
import { formatMrz, hash, arraysAreEqual, findSubarrayIndex } from '../src/utils/utils';
import { parseCertificate } from '../src/utils/certificates/handleCertificate';
import * as asn1 from 'asn1js';
import { Certificate } from 'pkijs';
import elliptic from 'elliptic';
import { parsePassportData, verifySignature } from '../src/utils/parsePassportData';
const sigAlgs: SignatureAlgorithm[] = [
'rsa_sha1_65537_2048',
'rsa_sha256_65537_2048',
'rsapss_sha256_65537_2048',
'ecdsa_sha256_secp256r1_256',
'ecdsa_sha1_secp256r1_256',
// 'ecdsa_sha384_secp384r1_384',
const testCases = [
{ dgHashAlgo: 'sha1', eContentHashAlgo: 'sha1', sigAlg: 'rsa_sha1_65537_2048' },
{ dgHashAlgo: 'sha1', eContentHashAlgo: 'sha1', sigAlg: 'rsa_sha256_65537_2048' },
{ dgHashAlgo: 'sha256', eContentHashAlgo: 'sha256', sigAlg: 'rsapss_sha256_65537_2048' },
{ dgHashAlgo: 'sha256', eContentHashAlgo: 'sha256', sigAlg: 'ecdsa_sha256_secp256r1_256' },
{ dgHashAlgo: 'sha1', eContentHashAlgo: 'sha1', sigAlg: 'ecdsa_sha1_secp256r1_256' },
];
describe('Mock Passport Data Generator', function () {
this.timeout(0);
sigAlgs.forEach((sigAlg) => {
testCases.forEach(({ dgHashAlgo, eContentHashAlgo, sigAlg }) => {
it(`should generate valid passport data for ${sigAlg}`, () => {
const passportData = genMockPassportData(sigAlg, 'FRA', '000101', '300101');
const passportData = genMockPassportData(
dgHashAlgo,
eContentHashAlgo,
sigAlg as SignatureAlgorithm,
'FRA',
'000101',
'300101'
);
expect(passportData).to.exist;
expect(verify(passportData)).to.be.true;
expect(verify(passportData, dgHashAlgo, eContentHashAlgo)).to.be.true;
});
});
});
function verify(passportData: PassportData): boolean {
const { mrz, dsc, eContent, signedAttr, encryptedDigest } = passportData;
const { signatureAlgorithm, hashFunction, hashLen, curve } = parseCertificate(dsc);
const formattedMrz = formatMrz(mrz);
const mrzHash = hash(hashFunction, formattedMrz);
const dg1HashOffset = findSubarrayIndex(eContent, mrzHash);
assert(dg1HashOffset !== -1, 'MRZ hash index not found in eContent');
console.error(
'\x1b[32m',
'signatureAlgorithm',
signatureAlgorithm,
' hashFunction',
hashFunction,
'eContent size',
eContent.length,
'signedAttr size',
signedAttr.length,
'\x1b[0m'
);
const concatHash = hash(hashFunction, eContent);
assert(
arraysAreEqual(concatHash, signedAttr.slice(signedAttr.length - hashLen)),
'concatHash is not at the right place in signedAttr'
);
function verify(passportData: PassportData, dgHashAlgo: string, eContentHashAlgo: string): boolean {
const passportMetaData = parsePassportData(passportData);
console.log('passportMetaData', passportMetaData);
if (signatureAlgorithm === 'ecdsa') {
const certBuffer = Buffer.from(
dsc.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1.fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data.result });
const publicKeyInfo = cert.subjectPublicKeyInfo;
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384';
const ec = new elliptic.ec(curveForElliptic);
expect(passportMetaData.dg1HashFunction).to.equal(dgHashAlgo);
expect(passportMetaData.eContentHashFunction).to.equal(eContentHashAlgo);
const key = ec.keyFromPublic(publicKeyBuffer);
const md = hashFunction === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const msgHash = md.digest().toHex();
const signature_crypto = Buffer.from(encryptedDigest).toString('hex');
return key.verify(msgHash, signature_crypto);
} else {
const cert = forge.pki.certificateFromPem(dsc);
const publicKey = cert.publicKey as forge.pki.rsa.PublicKey;
const md = forge.md[hashFunction].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const signature = Buffer.from(encryptedDigest).toString('binary');
if (signatureAlgorithm === 'rsapss') {
const pss = forge.pss.create({
md: forge.md[hashFunction].create(),
mgf: forge.mgf.mgf1.create(forge.md[hashFunction].create()),
saltLength: hashLen,
});
return publicKey.verify(md.digest().bytes(), signature, pss);
} else {
return publicKey.verify(md.digest().bytes(), signature);
}
}
return verifySignature(passportData, passportMetaData.signedAttrHashFunction);
}

File diff suppressed because it is too large Load Diff