mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-04 21:37:11 -04:00
fix: refactor and unit test
This commit is contained in:
parent
c10302b138
commit
ddd3f6ed09
4 changed files with 673 additions and 406 deletions
333
src/tools/certificate-key-parser/certificate-key-parser.infos.ts
Normal file
333
src/tools/certificate-key-parser/certificate-key-parser.infos.ts
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
import type {
|
||||||
|
Certificate,
|
||||||
|
Fingerprint,
|
||||||
|
Key,
|
||||||
|
PrivateKey, Signature,
|
||||||
|
} from 'sshpk';
|
||||||
|
import type * as openpgp from 'openpgp';
|
||||||
|
import * as forge from 'node-forge';
|
||||||
|
|
||||||
|
export interface LabelValue {
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
multiline?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
function onErrorReturnErrorMessage(func: () => any) {
|
||||||
|
try {
|
||||||
|
return func();
|
||||||
|
}
|
||||||
|
catch (e: any) {
|
||||||
|
return e.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buf2Hex(buffer: ArrayBuffer) { // buffer is an ArrayBuffer
|
||||||
|
return [...new Uint8Array(buffer)]
|
||||||
|
.map(x => x.toString(16).padStart(2, '0'))
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPublicKeyLabelValues(publicKey: Key) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'Public Key',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Key Type:',
|
||||||
|
value: publicKey.type,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Size:',
|
||||||
|
value: publicKey.size,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Comment:',
|
||||||
|
value: publicKey.comment,
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Curve:',
|
||||||
|
value: publicKey.curve ?? 'none',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (sha256):',
|
||||||
|
value: onErrorReturnErrorMessage(() => publicKey.fingerprint('sha256')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (sha512):',
|
||||||
|
value: onErrorReturnErrorMessage(() => publicKey.fingerprint('sha512')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
] as LabelValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPrivateKeyLabelValues(privateKey: PrivateKey) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'Private Key',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Key Type:',
|
||||||
|
value: privateKey.type,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Size:',
|
||||||
|
value: privateKey.size,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Comment:',
|
||||||
|
value: privateKey.comment,
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Curve:',
|
||||||
|
value: privateKey.curve,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (sha256):',
|
||||||
|
value: onErrorReturnErrorMessage(() => privateKey.fingerprint('sha256')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (sha512):',
|
||||||
|
value: onErrorReturnErrorMessage(() => privateKey.fingerprint('sha512')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
] as LabelValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCertificateLabelValues(cert: Certificate) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'Certificate',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subjects:',
|
||||||
|
value: cert.subjects?.map(s => s.toString()).join('\n'),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Issuer:',
|
||||||
|
value: cert.issuer.toString(),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subject Key:',
|
||||||
|
value: onErrorReturnErrorMessage(() => cert.subjectKey?.toString('ssh')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subject Key Type:',
|
||||||
|
value: cert.subjectKey?.type,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subject Size:',
|
||||||
|
value: cert.subjectKey?.size,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subject Comment:',
|
||||||
|
value: cert.subjectKey?.comment,
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subject Curve:',
|
||||||
|
value: cert.subjectKey?.curve ?? 'none',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Issuer Key:',
|
||||||
|
value: onErrorReturnErrorMessage(() => cert.issuerKey?.toString('ssh')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Serial:',
|
||||||
|
value: buf2Hex(cert.serial),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Purposes:',
|
||||||
|
value: cert.purposes?.join(', '),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Extensions:',
|
||||||
|
value: JSON.stringify(cert.getExtensions(), null, 2),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (sha256):',
|
||||||
|
value: onErrorReturnErrorMessage(() => cert.fingerprint('sha256')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (sha512):',
|
||||||
|
value: onErrorReturnErrorMessage(() => cert.fingerprint('sha512')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Certificate (pem):',
|
||||||
|
value: onErrorReturnErrorMessage(() => cert.toString('pem')),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
] as LabelValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPGPPublicKeyLabelValuesAsync(pgpPublicKey: openpgp.Key) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'PGP Public Key',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Creation Time:',
|
||||||
|
value: pgpPublicKey.getCreationTime().toString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Expiration Time:',
|
||||||
|
value: (await pgpPublicKey.getExpirationTime())?.toString() || '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Algorithm Info:',
|
||||||
|
value: JSON.stringify(pgpPublicKey.getAlgorithmInfo()),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint:',
|
||||||
|
value: pgpPublicKey.getFingerprint(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'User ID(s):',
|
||||||
|
value: pgpPublicKey.getUserIDs().join(', '),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Key ID(s):',
|
||||||
|
value: pgpPublicKey.getKeyIDs().map(k => k.toHex()).join(' ; '),
|
||||||
|
},
|
||||||
|
] as LabelValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPGPPrivateKeyLabelValuesAsync(pgpPrivateKey: openpgp.Key) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'PGP Private Key',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Creation Time:',
|
||||||
|
value: pgpPrivateKey.getCreationTime().toString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Expiration Time:',
|
||||||
|
value: (await pgpPrivateKey.getExpirationTime())?.toString() || '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Algorithm Info:',
|
||||||
|
value: JSON.stringify(pgpPrivateKey.getAlgorithmInfo()),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint:',
|
||||||
|
value: pgpPrivateKey.getFingerprint(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'User ID(s):',
|
||||||
|
value: pgpPrivateKey.getUserIDs().join(', '),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Key ID(s):',
|
||||||
|
value: pgpPrivateKey.getKeyIDs().map(k => k.toHex()).join(' ; '),
|
||||||
|
},
|
||||||
|
] as LabelValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCSRLabelValues(csr: forge.pki.Certificate) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'Certificate Signing Request',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subject:',
|
||||||
|
value: csr.subject?.attributes?.map(a => JSON.stringify(a, null, 2)).join('\n'),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Issuer:',
|
||||||
|
value: csr.issuer?.toString(),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Validity:',
|
||||||
|
value: JSON.stringify(csr.validity, null, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Signature:',
|
||||||
|
value: csr.signature,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Signature Oid:',
|
||||||
|
value: csr.signatureOid?.toString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Signature parameters:',
|
||||||
|
value: JSON.stringify(csr.signatureParameters, null, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Signing info:',
|
||||||
|
value: JSON.stringify(csr.siginfo, null, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Serial:',
|
||||||
|
value: csr.serialNumber?.toString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Extensions:',
|
||||||
|
value: JSON.stringify(csr.extensions, null, 2),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Public Key:',
|
||||||
|
value: onErrorReturnErrorMessage(() => forge.pki.publicKeyToPem(csr.publicKey)),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Public Key Fingerprint:',
|
||||||
|
value: onErrorReturnErrorMessage(() => forge.pki.getPublicKeyFingerprint(csr.publicKey)?.toHex()),
|
||||||
|
multiline: true,
|
||||||
|
},
|
||||||
|
] as LabelValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFingerprintLabelValues(fingerprint: Fingerprint) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'Fingerprint',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (hex):',
|
||||||
|
value: fingerprint.toString('hex'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (base64):',
|
||||||
|
value: fingerprint.toString('base64'),
|
||||||
|
},
|
||||||
|
] as LabelValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSignatureLabelValues(signature: Signature) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'Signature',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (asn1):',
|
||||||
|
value: signature.toString('asn1'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fingerprint (ssh):',
|
||||||
|
value: signature.toString('ssh'),
|
||||||
|
},
|
||||||
|
] as LabelValue[];
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { getKeyOrCertificateInfosAsync } from './certificate-key-parser.service';
|
||||||
|
|
||||||
|
const encryptedPrivateKey = /* NOSONAR */ `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
oimmuNBEFKy1F1rSP3NQvwcZVw==
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
|
`;
|
||||||
|
const openSSHPrivateKey = /* NOSONAR */ `-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
|
||||||
|
NhAAAAAwEAAQAAAQEA4r66AJdnJBwsKDyTr4QizQYMVhaFtcBcMcVuJHbKW/DtG985oA2V
|
||||||
|
hJRfcBz8MKNS9iTLRkgq4yoTVCIi5FDVU4EnQbLMoLfN2og6PpgSSL59bPUvYoenp6RS1i
|
||||||
|
R606eVakH/J6IIiadHMWBrLjCiChf5U/bvuSkUQWi0YLH9hI6Nw+S9MdwzBofshZZdww9Y
|
||||||
|
4udrWEVdfGrxWv5gjlaquxYZAnfaYCI0Pgh9v1nEALFufOVi1onUZaxduyvsLoQnXiwP2c
|
||||||
|
fWXsBYmjfViTTADTvHTLCF9IH+6heGk2WJkosgiajmMlc+1U7Xs+r5ZJ0ikt0ioydPN8Hi
|
||||||
|
LnVih6lENwAAA7hrsy+Ha7MvhwAAAAdzc2gtcnNhAAABAQDivroAl2ckHCwoPJOvhCLNBg
|
||||||
|
xWFoW1wFwxxW4kdspb8O0b3zmgDZWElF9wHPwwo1L2JMtGSCrjKhNUIiLkUNVTgSdBssyg
|
||||||
|
t83aiDo+mBJIvn1s9S9ih6enpFLWJHrTp5VqQf8nogiJp0cxYGsuMKIKF/lT9u+5KRRBaL
|
||||||
|
Rgsf2Ejo3D5L0x3DMGh+yFll3DD1ji52tYRV18avFa/mCOVqq7FhkCd9pgIjQ+CH2/WcQA
|
||||||
|
sW585WLWidRlrF27K+wuhCdeLA/Zx9ZewFiaN9WJNMANO8dMsIX0gf7qF4aTZYmSiyCJqO
|
||||||
|
YyVz7VTtez6vlknSKS3SKjJ083weIudWKHqUQ3AAAAAwEAAQAAAQBmKTj0+0JlaqwalPCV
|
||||||
|
rBth9M+qGgu0kC753dJ6a2tRcYPjgvgbvQMY8SDvCqA16eB/NqS/zdRE9bgvuBGwfRsgvJ
|
||||||
|
hLaZv47de6FpbnjOzwCaPJa88lvak0Rz1rbpRIuMEBVyr3WHIwU0YoYSDpdtALbDHSOvhX
|
||||||
|
nMKblelvh8KJ7jelix2R3llvcYexKdS66zzP7nPj5x8d1FDo2cxqWsy2aQxMlbZGTd3ujQ
|
||||||
|
ABzZGvI3L0tJRf4sPph/eLS28/teAExp5Uo9DuehqgU33iAYOaO2vZGqQJxBbaVtiarVK1
|
||||||
|
kRQLBrhieMIUJ9XHSwDn74VHWtBNfocTSPe6vbVMjLpBAAAAgGBTluv8WHqG1JTauYNjBI
|
||||||
|
EhSKL96MrIZR+fytEg3gcxitPnpQiPTP6XHXpQ7fxVk25bYvCj4QNi00jW6kBR46Zh90NI
|
||||||
|
nKgYvxdYoA5A7L6JvvByy00SbLssiM7kf3ByT/4EA8S911Q4cks8lKrwEUw+UzqTBR6QdG
|
||||||
|
JyZQQcUJa+AAAAgQDyIYjECyG91/X+zFYcecW+wWyLBzyEvOxFlRd4tZnvWknQTdtFqTlN
|
||||||
|
orTT+un1ygKe0DkfwXSbbjE69+xxlMtPQ2X6wd2mUruvtyBv1R8Kfj+doY5lFUfCEKj88u
|
||||||
|
ck1+Ol1K+KDnvlYZVnb5eCvMxmEMqyD+eTQ2EcNAJtjNmuDQAAAIEA77uU45tseIe9E6OZ
|
||||||
|
Hum2bUxQmqkpjrNCECiTJR99NUx+22sBZwrMAt3QzBwgSogQhLKAw+keEUG6zAl7UA6Lsc
|
||||||
|
vJdDllY2vYMRW9LZ1XNCxvl0i6QUsT8l9hwA9GuMQN1m6NRU+cnEU87KIXVBb+DRyZwo21
|
||||||
|
4WRkAc1Ru/KtrlMAAAAAAQID
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
||||||
|
`;
|
||||||
|
|
||||||
|
const formatsData = [
|
||||||
|
{
|
||||||
|
input: `
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
xjMEZkHgaRYJKwYBBAHaRw8BAQdAdCmEzdpkjMzOoNkzgDFk/CHd+6uYAWkZ
|
||||||
|
BPbjEzTJWtfNAMKMBBAWCgA+BYJmQeBpBAsJBwgJkEDKj7jnGr9wAxUICgQW
|
||||||
|
AAIBAhkBApsDAh4BFiEExfkkog7+aHz7TqepQMqPuOcav3AAAJaaAQCayvFQ
|
||||||
|
jxFbC7oOzX+8wOV8gmXVXXqI5dtLQYY3SeyqmwD/ftVwwe6Prl0vVFyLB/5y
|
||||||
|
lIpAti8AK1Lv8hIezzOx4QDOOARmQeBpEgorBgEEAZdVAQUBAQdA2jU3Rmt7
|
||||||
|
nMFvqyjgKdVjK5o2CQI2vJiSzn8cfV1piEgDAQgHwngEGBYKACoFgmZB4GkJ
|
||||||
|
kEDKj7jnGr9wApsMFiEExfkkog7+aHz7TqepQMqPuOcav3AAABI0AQCMW4Hg
|
||||||
|
FuIaZk9LVQsUmNknj4a70fzwDYWUYvq0C1iy/QD+KXvLKfcmky5OXJA7RsRV
|
||||||
|
SN2a4SE4c8FH22uyirzyUww=
|
||||||
|
=w51K
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
`,
|
||||||
|
pass: '',
|
||||||
|
type: 'PGP Public Key',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// NOSONAR
|
||||||
|
input: `
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
xVgEZkHgaRYJKwYBBAHaRw8BAQdAdCmEzdpkjMzOoNkzgDFk/CHd+6uYAWkZ
|
||||||
|
BPbjEzTJWtcAAQDXcDgEziqd9ZO/OpoyblRRxAOgPq2y8zTitwTz+ixX7RCe
|
||||||
|
zQDCjAQQFgoAPgWCZkHgaQQLCQcICZBAyo+45xq/cAMVCAoEFgACAQIZAQKb
|
||||||
|
AwIeARYhBMX5JKIO/mh8+06nqUDKj7jnGr9wAACWmgEAmsrxUI8RWwu6Ds1/
|
||||||
|
vMDlfIJl1V16iOXbS0GGN0nsqpsA/37VcMHuj65dL1Rciwf+cpSKQLYvACtS
|
||||||
|
7/ISHs8zseEAx10EZkHgaRIKKwYBBAGXVQEFAQEHQNo1N0Zre5zBb6so4CnV
|
||||||
|
YyuaNgkCNryYks5/HH1daYhIAwEIBwAA/2PxYHVWBmkLD9eiFDLJ0EtspWQ+
|
||||||
|
JKui86xylduxQWngEIrCeAQYFgoAKgWCZkHgaQmQQMqPuOcav3ACmwwWIQTF
|
||||||
|
+SSiDv5ofPtOp6lAyo+45xq/cAAAEjQBAIxbgeAW4hpmT0tVCxSY2SePhrvR
|
||||||
|
/PANhZRi+rQLWLL9AP4pe8sp9yaTLk5ckDtGxFVI3ZrhIThzwUfba7KKvPJT
|
||||||
|
DA==
|
||||||
|
=hSgY
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
|
`,
|
||||||
|
pass: '',
|
||||||
|
type: 'PGP Private Key',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `
|
||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIClTCCAX0CAQAwUDERMA8GA1UEAxMIdGVzdC5jb20xDzANBgNVBAYTBkZyYW5j
|
||||||
|
ZTELMAkGA1UECBMCRlIxDjAMBgNVBAcTBVBhcmlzMQ0wCwYDVQQKEwRUZXN0MIIB
|
||||||
|
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnIUCiMFffkHGuAhwTaW84uh7
|
||||||
|
/03KcfQAZB/bZKqLaxtcBGryTB1gHFSsl3uFlW+tIcjsboWnQ2JB0J1Z5Fp4a6IA
|
||||||
|
/62S6GTo6dAd9f73TR+P2vQghZOtiCoc7CN2KlosIx/EWMcMjq+CBzLRjjOOR8tX
|
||||||
|
Yn4ZAhPInO1ZGPMEpfEEfn44aJFRGaMy4KEU+RpTzFKFW6bialvKC3yGPegQ4wcz
|
||||||
|
AqvyUc9WUwG53HYLSJHldg8tZnpiJBNUh8mXiIiw51MFJ4Q9RVnz9vuoHgC6FmUv
|
||||||
|
qlg/R4gjGGfjDhAIUtz+Y98Dl+xfLmD+EzY7KQ1ur412BvQ8rXankNGLA2ea+wID
|
||||||
|
AQABoAAwDQYJKoZIhvcNAQEFBQADggEBABdtkhFSwgaXZWTcKrz6oarvuaQkrjvs
|
||||||
|
Nk9lUs1h/dfhJpnE3iZA0CuNp5PVQRdC2g+/37r21/udjNFdrX1Rm6/ldG0b2xDu
|
||||||
|
nQYZcLpIVB0fZ2TB+FHthmGw175I2niWIfNJQhIqnWJXi8unkGTMP2cD6j3axtMi
|
||||||
|
K8MUVPhWmL11ojEXItG35AU79G6GhFxel9wIByqsXreCUyOcrpYCHy2Fv85ivdE1
|
||||||
|
JyEQ2tE/f+cKwNg4yJNFoCoHSSFRn61F12J4m2nwpQ77VfD66oVkWtk/gYMrwx0d
|
||||||
|
4FlJNs+NtZDlcM7fJLNo7YsMdne7hl4aL6WG96kdWdxYEt/2dl3WXbY=
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
||||||
|
`,
|
||||||
|
pass: '',
|
||||||
|
type: 'Certificate Signing Request',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDivroAl2ckHCwoPJOvhCLNBgxWFoW1wFwxxW4kdspb8O0b3zmgDZWElF9wHPwwo1L2JMtGSCrjKhNUIiLkUNVTgSdBssygt83aiDo+mBJIvn1s9S9ih6enpFLWJHrTp5VqQf8nogiJp0cxYGsuMKIKF/lT9u+5KRRBaLRgsf2Ejo3D5L0x3DMGh+yFll3DD1ji52tYRV18avFa/mCOVqq7FhkCd9pgIjQ+CH2/WcQAsW585WLWidRlrF27K+wuhCdeLA/Zx9ZewFiaN9WJNMANO8dMsIX0gf7qF4aTZYmSiyCJqOYyVz7VTtez6vlknSKS3SKjJ083weIudWKHqUQ3
|
||||||
|
`,
|
||||||
|
pass: '',
|
||||||
|
type: 'Public Key',
|
||||||
|
title: 'ssh-rsa Public Key',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: openSSHPrivateKey,
|
||||||
|
pass: '',
|
||||||
|
type: 'Private Key',
|
||||||
|
title: 'Unencrypted Private Key',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `
|
||||||
|
SHA256:qflg623OemnYEHDwUafq+XuMoB0UdJ+Ks44kHcWxDyM
|
||||||
|
`,
|
||||||
|
pass: '',
|
||||||
|
type: 'Fingerprint',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDQDCCAiigAwIBAgIJK59gK0GUbZO3MA0GCSqGSIb3DQEBBQUAMFAxETAPBgNV
|
||||||
|
BAMTCHRlc3QuY29tMQ8wDQYDVQQGEwZGcmFuY2UxCzAJBgNVBAgTAkZSMQ4wDAYD
|
||||||
|
VQQHEwVQYXJpczENMAsGA1UEChMEVGVzdDAeFw0yNDA1MTMwOTQ4MTVaFw0yNTA1
|
||||||
|
MTMwOTQ4MTVaMFAxETAPBgNVBAMTCHRlc3QuY29tMQ8wDQYDVQQGEwZGcmFuY2Ux
|
||||||
|
CzAJBgNVBAgTAkZSMQ4wDAYDVQQHEwVQYXJpczENMAsGA1UEChMEVGVzdDCCASIw
|
||||||
|
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMKrE3C9tUtmvHZkIwEBf1h5N7KC
|
||||||
|
FoXowfNZxKK7SHWcnQjBdv0ziqsU+GmcUqUD1GymMcBweqw4TQVg0a/UwdYIUTuQ
|
||||||
|
GXGx4ULCXKHv/NfmVSWcMsOZHAR4m/yEzTB/ZjKMSrqnIWyOdusDMRn4VRoAtrKO
|
||||||
|
/FM+SDJ6wvnJ/jNoZJXktq9avYduEi+heNekIF6NYM9clzm9Ff3Evf89KuigBcsu
|
||||||
|
rgL+S8PjotCwxMgzOWV4/paeeQluqYeU94prWIASS/D3elH7qFTAUnafBICFN2zs
|
||||||
|
XWY6ZFCR8QrDI5F/8KELq/3BaLQBxpIi9SmADLWqnPOu+6H5rzr2YV8LaxMCAwEA
|
||||||
|
AaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAvQwDQYJKoZIhvcNAQEFBQAD
|
||||||
|
ggEBAKhrUNnWe0VmgefvfwsAqrbk0Z6PwaibIl/l5I9oh1qM01J9BFHpvomhcLxu
|
||||||
|
cmIpD6nAqtkNyvsXtFAnZG3WNaf45yyd153wSa0QnrNo2GRH9quktm4DaRIIP7qq
|
||||||
|
EdtApYCeT16LvAGYUH3ubCdom8w6DkukLg8qMrXMywSZlx85jlJfifPvMKsJmm/a
|
||||||
|
QAq1H3cYaaj0DocF1rCP+hLzvsuM7UwS2JOK8Mw49kYPBTbCVmRDOE1rhlDIO8Kw
|
||||||
|
V7CCFr4NXsyRlM0TpKdspOmxJiyxmk6DoVgp9PeqfoyDAC9TJU0VJ6A2x+AfjK4O
|
||||||
|
Wg6xDXMx6dk6Rhh8yqGrmx05QM8=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
`,
|
||||||
|
pass: '',
|
||||||
|
type: 'Certificate',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `
|
||||||
|
c6:b9:73:b8:68:49:33:ad:27:51:bb:6c:16:e7:9c:da:dd:e3:92:15
|
||||||
|
`,
|
||||||
|
pass: '',
|
||||||
|
type: 'Fingerprint',
|
||||||
|
title: 'HEX Fingerprint',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: encryptedPrivateKey,
|
||||||
|
pass: 'test',
|
||||||
|
type: 'Private Key',
|
||||||
|
title: 'Encrypted Private Key',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('certificate-key-parser', () => {
|
||||||
|
for (const format of formatsData) {
|
||||||
|
const { input, pass, type, title } = format;
|
||||||
|
it(`Parse '${title ?? type}' format with right type (${type})`, async () => {
|
||||||
|
const { values } = await getKeyOrCertificateInfosAsync(input, pass);
|
||||||
|
const result_type = values.find(v => v.label === 'Type:')?.value;
|
||||||
|
|
||||||
|
expect(result_type).toBe(type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,129 @@
|
||||||
|
import type { Buffer } from 'node:buffer';
|
||||||
|
import {
|
||||||
|
parseCertificate, parseFingerprint,
|
||||||
|
parseKey,
|
||||||
|
parsePrivateKey,
|
||||||
|
parseSignature,
|
||||||
|
} from 'sshpk';
|
||||||
|
import type {
|
||||||
|
AlgorithmType,
|
||||||
|
Certificate,
|
||||||
|
CertificateFormat,
|
||||||
|
Fingerprint,
|
||||||
|
Key,
|
||||||
|
PrivateKey, Signature, SignatureFormatType,
|
||||||
|
} from 'sshpk';
|
||||||
|
import { Base64 } from 'js-base64';
|
||||||
|
import * as openpgp from 'openpgp';
|
||||||
|
import * as forge from 'node-forge';
|
||||||
|
import { type LabelValue, getCSRLabelValues, getCertificateLabelValues, getFingerprintLabelValues, getPGPPrivateKeyLabelValuesAsync, getPGPPublicKeyLabelValuesAsync, getPrivateKeyLabelValues, getPublicKeyLabelValues, getSignatureLabelValues } from './certificate-key-parser.infos';
|
||||||
|
|
||||||
|
export async function getKeyOrCertificateInfosAsync(keyOrCertificateValue: string | Buffer, passphrase: string) {
|
||||||
|
try {
|
||||||
|
const canParse = (value: string | Buffer, parseFunction: (value: string | Buffer) => any) => {
|
||||||
|
try {
|
||||||
|
return parseFunction(value);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const canParseAsync = async (value: string | Buffer, parseFunction: (value: string | Buffer) => Promise<any>) => {
|
||||||
|
try {
|
||||||
|
return await parseFunction(value);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputKeyOrCertificateValue = (typeof keyOrCertificateValue === 'string' ? keyOrCertificateValue?.trim() : keyOrCertificateValue);
|
||||||
|
|
||||||
|
const privateKey = canParse(inputKeyOrCertificateValue,
|
||||||
|
value => parsePrivateKey(value, 'auto', { passphrase })) as PrivateKey;
|
||||||
|
if (privateKey) {
|
||||||
|
return {
|
||||||
|
values: getPrivateKeyLabelValues(privateKey),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const publicKey = canParse(inputKeyOrCertificateValue, parseKey) as Key;
|
||||||
|
if (publicKey) {
|
||||||
|
return { values: getPublicKeyLabelValues(publicKey) };
|
||||||
|
}
|
||||||
|
|
||||||
|
const pgpPrivateKey = await canParseAsync(inputKeyOrCertificateValue, value => openpgp.readPrivateKey({ armoredKey: value.toString() })) as openpgp.Key;
|
||||||
|
if (pgpPrivateKey) {
|
||||||
|
return { values: await getPGPPrivateKeyLabelValuesAsync(pgpPrivateKey) };
|
||||||
|
}
|
||||||
|
|
||||||
|
const pgpPublicKey = await canParseAsync(inputKeyOrCertificateValue, value => openpgp.readKey({ armoredKey: value.toString() })) as openpgp.Key;
|
||||||
|
if (pgpPublicKey) {
|
||||||
|
return { values: await getPGPPublicKeyLabelValuesAsync(pgpPublicKey) };
|
||||||
|
}
|
||||||
|
|
||||||
|
const cert = canParse(inputKeyOrCertificateValue, (value) => {
|
||||||
|
for (const format of ['openssh', 'pem', 'x509']) {
|
||||||
|
try {
|
||||||
|
return parseCertificate(value, format as CertificateFormat);
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}) as Certificate;
|
||||||
|
if (cert) {
|
||||||
|
let certificateX509DER = '';
|
||||||
|
try {
|
||||||
|
certificateX509DER = Base64.fromUint8Array(cert.toBuffer('x509'));
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
|
||||||
|
return { values: getCertificateLabelValues(cert), certificateX509DER };
|
||||||
|
}
|
||||||
|
|
||||||
|
const csr = canParse(inputKeyOrCertificateValue, (value) => {
|
||||||
|
return forge.pki.certificationRequestFromPem(value.toString(), false, false);
|
||||||
|
}) as forge.pki.Certificate;
|
||||||
|
if (csr) {
|
||||||
|
return { values: getCSRLabelValues(csr) };
|
||||||
|
}
|
||||||
|
|
||||||
|
const fingerprint = canParse(inputKeyOrCertificateValue, value => parseFingerprint(value.toString())) as Fingerprint;
|
||||||
|
if (fingerprint) {
|
||||||
|
return { values: getFingerprintLabelValues(fingerprint) };
|
||||||
|
}
|
||||||
|
|
||||||
|
const signature = canParse(inputKeyOrCertificateValue, (value) => {
|
||||||
|
//
|
||||||
|
for (const algo of ['dsa', 'rsa', 'ecdsa', 'ed25519']) {
|
||||||
|
for (const format of ['asn1', 'ssh', 'raw']) {
|
||||||
|
try {
|
||||||
|
return parseSignature(value, algo as AlgorithmType, format as SignatureFormatType);
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}) as Signature;
|
||||||
|
if (signature) {
|
||||||
|
return { values: getSignatureLabelValues(signature) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
label: 'Type:',
|
||||||
|
value: 'Unknown format or invalid passphrase',
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (e: any) {
|
||||||
|
return {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
label: 'Error:',
|
||||||
|
value: e.toString(),
|
||||||
|
}] as LabelValue[],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Buffer } from 'node:buffer';
|
import { Buffer } from 'node:buffer';
|
||||||
import {
|
|
||||||
parseCertificate, parseFingerprint,
|
|
||||||
parseKey,
|
|
||||||
parsePrivateKey,
|
|
||||||
parseSignature,
|
|
||||||
} from 'sshpk';
|
|
||||||
import type {
|
|
||||||
AlgorithmType,
|
|
||||||
Certificate,
|
|
||||||
CertificateFormat,
|
|
||||||
Fingerprint,
|
|
||||||
Key,
|
|
||||||
PrivateKey, Signature, SignatureFormatType,
|
|
||||||
} from 'sshpk';
|
|
||||||
import { Base64 } from 'js-base64';
|
|
||||||
import * as openpgp from 'openpgp';
|
|
||||||
import * as forge from 'node-forge';
|
|
||||||
import { useDownloadFileFromBase64 } from '@/composable/downloadBase64';
|
|
||||||
|
|
||||||
function buf2Hex(buffer: ArrayBuffer) { // buffer is an ArrayBuffer
|
import { getKeyOrCertificateInfosAsync } from './certificate-key-parser.service';
|
||||||
return [...new Uint8Array(buffer)]
|
import { type LabelValue } from './certificate-key-parser.infos';
|
||||||
.map(x => x.toString(16).padStart(2, '0'))
|
import { useDownloadFileFromBase64 } from '@/composable/downloadBase64';
|
||||||
.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
const inputKeyOrCertificate = ref('');
|
const inputKeyOrCertificate = ref('');
|
||||||
const passphrase = ref('');
|
const passphrase = ref('');
|
||||||
|
@ -56,394 +36,15 @@ function downloadX509DERFile() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LabelValue {
|
|
||||||
label: string
|
|
||||||
value: string
|
|
||||||
multiline?: boolean
|
|
||||||
}
|
|
||||||
const parsedSections = computedAsync<LabelValue[]>(async () => {
|
const parsedSections = computedAsync<LabelValue[]>(async () => {
|
||||||
try {
|
|
||||||
certificateX509DER.value = '';
|
|
||||||
const onErrorReturnErrorMessage = (func: () => any) => {
|
|
||||||
try {
|
|
||||||
return func();
|
|
||||||
}
|
|
||||||
catch (e: any) {
|
|
||||||
return e.toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const canParse = (value: string | Buffer, parseFunction: (value: string | Buffer) => any) => {
|
|
||||||
try {
|
|
||||||
return parseFunction(value);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const canParseAsync = async (value: string | Buffer, parseFunction: (value: string | Buffer) => Promise<any>) => {
|
|
||||||
try {
|
|
||||||
return await parseFunction(value);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const inputKeyOrCertificateValue
|
const inputKeyOrCertificateValue
|
||||||
= inputKeyOrCertificate.value !== ''
|
= inputKeyOrCertificate.value !== ''
|
||||||
? inputKeyOrCertificate.value
|
? inputKeyOrCertificate.value
|
||||||
: fileInput.value;
|
: fileInput.value;
|
||||||
const publicKey = canParse(inputKeyOrCertificateValue, parseKey) as Key;
|
|
||||||
if (publicKey) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'Public Key',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Key Type: ',
|
|
||||||
value: publicKey.type,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Size: ',
|
|
||||||
value: publicKey.size,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Comment: ',
|
|
||||||
value: publicKey.comment,
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Curve: ',
|
|
||||||
value: publicKey.curve ?? 'none',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (sha256): ',
|
|
||||||
value: onErrorReturnErrorMessage(() => publicKey.fingerprint('sha256')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (sha512): ',
|
|
||||||
value: onErrorReturnErrorMessage(() => publicKey.fingerprint('sha512')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
] as LabelValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const privateKey = canParse(inputKeyOrCertificateValue,
|
const { values, certificateX509DER: certPEM } = await getKeyOrCertificateInfosAsync(inputKeyOrCertificateValue, passphrase.value);
|
||||||
value => parsePrivateKey(value, 'auto', { passphrase: passphrase.value })) as PrivateKey;
|
certificateX509DER.value = certPEM || '';
|
||||||
if (privateKey) {
|
return values;
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'Private Key',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Key Type: ',
|
|
||||||
value: privateKey.type,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Size: ',
|
|
||||||
value: privateKey.size,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Comment: ',
|
|
||||||
value: privateKey.comment,
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Curve: ',
|
|
||||||
value: privateKey.curve,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (sha256): ',
|
|
||||||
value: onErrorReturnErrorMessage(() => privateKey.fingerprint('sha256')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (sha512): ',
|
|
||||||
value: onErrorReturnErrorMessage(() => privateKey.fingerprint('sha512')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
] as LabelValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const cert = canParse(inputKeyOrCertificateValue, (value) => {
|
|
||||||
for (const format of ['openssh', 'pem', 'x509']) {
|
|
||||||
try {
|
|
||||||
return parseCertificate(value, format as CertificateFormat);
|
|
||||||
}
|
|
||||||
catch {}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}) as Certificate;
|
|
||||||
if (cert) {
|
|
||||||
try {
|
|
||||||
certificateX509DER.value = Base64.fromUint8Array(cert.toBuffer('x509'));
|
|
||||||
}
|
|
||||||
catch {}
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'Certificate',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Subjects: ',
|
|
||||||
value: cert.subjects.map(s => s.toString()).join('\n'),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Issuer: ',
|
|
||||||
value: cert.issuer.toString(),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Subject Key: ',
|
|
||||||
value: onErrorReturnErrorMessage(() => cert.subjectKey?.toString('ssh')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Subject Key Type: ',
|
|
||||||
value: cert.subjectKey?.type,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Subject Size: ',
|
|
||||||
value: cert.subjectKey?.size,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Subject Comment: ',
|
|
||||||
value: cert.subjectKey?.comment,
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Subject Curve: ',
|
|
||||||
value: cert.subjectKey?.curve ?? 'none',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Issuer Key: ',
|
|
||||||
value: onErrorReturnErrorMessage(() => cert.issuerKey?.toString('ssh')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Serial: ',
|
|
||||||
value: buf2Hex(cert.serial),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Purposes: ',
|
|
||||||
value: cert.purposes?.join(', '),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Extensions: ',
|
|
||||||
value: JSON.stringify(cert.getExtensions(), null, 2),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (sha256): ',
|
|
||||||
value: onErrorReturnErrorMessage(() => cert.fingerprint('sha256')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (sha512): ',
|
|
||||||
value: onErrorReturnErrorMessage(() => cert.fingerprint('sha512')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Certificate (pem): ',
|
|
||||||
value: onErrorReturnErrorMessage(() => cert.toString('pem')),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
] as LabelValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const csr = canParse(inputKeyOrCertificateValue, (value) => {
|
|
||||||
return forge.pki.certificationRequestFromPem(value.toString(), true, false);
|
|
||||||
}) as forge.pki.Certificate;
|
|
||||||
if (csr) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'Certificate Signing Request',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Subject: ',
|
|
||||||
value: csr.subject.attributes.map(a => JSON.stringify(a, null, 2)).join('\n'),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Issuer: ',
|
|
||||||
value: csr.issuer?.toString(),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Validity: ',
|
|
||||||
value: JSON.stringify(csr.validity, null, 2),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Signature: ',
|
|
||||||
value: csr.signature,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Signature Oid: ',
|
|
||||||
value: csr.signatureOid?.toString(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Signature parameters: ',
|
|
||||||
value: JSON.stringify(csr.signatureParameters, null, 2),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Signing info: ',
|
|
||||||
value: JSON.stringify(csr.siginfo, null, 2),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Serial: ',
|
|
||||||
value: csr.serialNumber?.toString(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Extensions: ',
|
|
||||||
value: JSON.stringify(csr.extensions, null, 2),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Public Key: ',
|
|
||||||
value: onErrorReturnErrorMessage(() => forge.pki.publicKeyToPem(csr.publicKey)),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Public Key Fingerprint:',
|
|
||||||
value: onErrorReturnErrorMessage(() => forge.pki.getPublicKeyFingerprint(csr.publicKey)?.toHex()),
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
] as LabelValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const fingerprint = canParse(inputKeyOrCertificateValue, value => parseFingerprint(value.toString())) as Fingerprint;
|
|
||||||
if (fingerprint) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'Fingerprint',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (hex): ',
|
|
||||||
value: fingerprint.toString('hex'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (base64): ',
|
|
||||||
value: fingerprint.toString('base64'),
|
|
||||||
},
|
|
||||||
] as LabelValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const pgpPrivateKey = await canParseAsync(inputKeyOrCertificateValue, value => openpgp.readPrivateKey({ armoredKey: value.toString() })) as openpgp.Key;
|
|
||||||
if (pgpPrivateKey) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'PGP Private Key',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Creation Time: ',
|
|
||||||
value: pgpPrivateKey.getCreationTime().toString(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Expiration Time: ',
|
|
||||||
value: (await pgpPrivateKey.getExpirationTime())?.toString() || '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Algorithm Info: ',
|
|
||||||
value: JSON.stringify(pgpPrivateKey.getAlgorithmInfo()),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint: ',
|
|
||||||
value: pgpPrivateKey.getFingerprint(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'User ID(s): ',
|
|
||||||
value: pgpPrivateKey.getUserIDs().join(', '),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Key ID(s): ',
|
|
||||||
value: pgpPrivateKey.getKeyIDs().map(k => k.toHex()).join(' ; '),
|
|
||||||
},
|
|
||||||
] as LabelValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const pgpPublicKey = await canParseAsync(inputKeyOrCertificateValue, value => openpgp.readKey({ armoredKey: value.toString() })) as openpgp.Key;
|
|
||||||
if (pgpPublicKey) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'PGP Public Key',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Creation Time: ',
|
|
||||||
value: pgpPublicKey.getCreationTime().toString(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Expiration Time: ',
|
|
||||||
value: (await pgpPublicKey.getExpirationTime())?.toString() || '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Algorithm Info: ',
|
|
||||||
value: JSON.stringify(pgpPublicKey.getAlgorithmInfo()),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint: ',
|
|
||||||
value: pgpPublicKey.getFingerprint(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'User ID(s): ',
|
|
||||||
value: pgpPublicKey.getUserIDs().join(', '),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Key ID(s): ',
|
|
||||||
value: pgpPublicKey.getKeyIDs().map(k => k.toHex()).join(' ; '),
|
|
||||||
},
|
|
||||||
] as LabelValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const signature = canParse(inputKeyOrCertificateValue, (value) => {
|
|
||||||
//
|
|
||||||
for (const algo of ['dsa', 'rsa', 'ecdsa', 'ed25519']) {
|
|
||||||
for (const format of ['asn1', 'ssh', 'raw']) {
|
|
||||||
try {
|
|
||||||
return parseSignature(value, algo as AlgorithmType, format as SignatureFormatType);
|
|
||||||
}
|
|
||||||
catch {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}) as Signature;
|
|
||||||
if (signature) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'Signature',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (asn1): ',
|
|
||||||
value: signature.toString('asn1'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Fingerprint (ssh): ',
|
|
||||||
value: signature.toString('ssh'),
|
|
||||||
},
|
|
||||||
] as LabelValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Type: ',
|
|
||||||
value: 'Unknown format or invalid passphrase',
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
catch (e: any) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Error: ',
|
|
||||||
value: e.toString(),
|
|
||||||
}] as LabelValue[];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -465,6 +66,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => {
|
||||||
placeholder="Your Public Key / Private Key / Signature / Fingerprint / Certificate..."
|
placeholder="Your Public Key / Private Key / Signature / Fingerprint / Certificate..."
|
||||||
multiline
|
multiline
|
||||||
rows="8"
|
rows="8"
|
||||||
|
data-test-id="input"
|
||||||
/>
|
/>
|
||||||
</c-card>
|
</c-card>
|
||||||
|
|
||||||
|
@ -473,6 +75,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => {
|
||||||
label="Passphrase (for encrypted keys):"
|
label="Passphrase (for encrypted keys):"
|
||||||
placeholder="Passphrase (for encrypted keys)..."
|
placeholder="Passphrase (for encrypted keys)..."
|
||||||
type="password"
|
type="password"
|
||||||
|
data-test-id="pass"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<n-divider />
|
<n-divider />
|
||||||
|
@ -481,6 +84,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => {
|
||||||
v-for="{ label, value, multiline } of parsedSections"
|
v-for="{ label, value, multiline } of parsedSections"
|
||||||
:key="label"
|
:key="label"
|
||||||
:label="label"
|
:label="label"
|
||||||
|
:data-test-id="label"
|
||||||
label-position="left"
|
label-position="left"
|
||||||
label-width="100px"
|
label-width="100px"
|
||||||
label-align="right"
|
label-align="right"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue