mirror of
https://github.com/selfxyz/self.git
synced 2026-01-10 15:18:18 -05:00
merge dev
This commit is contained in:
@@ -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
@@ -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-----
|
||||
@@ -0,0 +1 @@
|
||||
0D8719B1C1968AE52BCA6B5FF0C7195751CFB8E9
|
||||
@@ -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
|
||||
@@ -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-----
|
||||
@@ -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-----
|
||||
@@ -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-----
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIGkAgEBBDDabeMgcheTsizT6aH0CiXxb1gvSHQNjbcqJCooAljzzEyLdAeCOhoA
|
||||
ureFOIfii2ugBwYFK4EEACKhZANiAASXB5JLXDhIpuPQifVyYMm2M8AO+vnQDtt+
|
||||
IfEYl3aDBvnwNUQjomlk8H2TT2fuFlWS+vfqinxqERFu9Aom8ghJSboCPdXwLfg/
|
||||
KRj8TTjM5rLeXDWCw1zjPFGfP4Pn6zo=
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -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' };
|
||||
}
|
||||
}
|
||||
331
common/src/utils/certificate_parsing/parseCertificateSimple.ts
Normal file
331
common/src/utils/certificate_parsing/parseCertificateSimple.ts
Normal 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';
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 };
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
49
common/src/utils/circuitsName.ts
Normal file
49
common/src/utils/circuitsName.ts
Normal 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;
|
||||
}
|
||||
@@ -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()),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
85
common/src/utils/elliptic.ts
Normal file
85
common/src/utils/elliptic.ts
Normal 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;
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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,
|
||||
|
||||
239
common/src/utils/parsePassportData.ts
Normal file
239
common/src/utils/parsePassportData.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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 } {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
4765
common/yarn.lock
4765
common/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user