@andrewheberle/serverless-ssh-ca 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +174 -1
  2. package/dist/api/operations.d.ts +50 -0
  3. package/dist/api/operations.d.ts.map +1 -0
  4. package/dist/api/operations.js +264 -0
  5. package/dist/api/operations.js.map +1 -0
  6. package/dist/api/schema.d.ts +72 -0
  7. package/dist/api/schema.d.ts.map +1 -0
  8. package/dist/api/schema.js +114 -0
  9. package/dist/api/schema.js.map +1 -0
  10. package/dist/api/v3/index.d.ts.map +1 -1
  11. package/dist/api/v3/index.js +13 -202
  12. package/dist/api/v3/index.js.map +1 -1
  13. package/dist/api/v3/schema.d.ts +23 -68
  14. package/dist/api/v3/schema.d.ts.map +1 -1
  15. package/dist/api/v3/schema.js +18 -104
  16. package/dist/api/v3/schema.js.map +1 -1
  17. package/dist/api/v4/index.d.ts +8 -0
  18. package/dist/api/v4/index.d.ts.map +1 -0
  19. package/dist/api/v4/index.js +155 -0
  20. package/dist/api/v4/index.js.map +1 -0
  21. package/dist/api/v4/schema.d.ts +268 -0
  22. package/dist/api/v4/schema.d.ts.map +1 -0
  23. package/dist/api/v4/schema.js +186 -0
  24. package/dist/api/v4/schema.js.map +1 -0
  25. package/dist/certificate.d.ts +9 -6
  26. package/dist/certificate.d.ts.map +1 -1
  27. package/dist/certificate.js +55 -99
  28. package/dist/certificate.js.map +1 -1
  29. package/dist/db/index.d.ts +68 -9
  30. package/dist/db/index.d.ts.map +1 -1
  31. package/dist/db/index.js +165 -49
  32. package/dist/db/index.js.map +1 -1
  33. package/dist/db/migrations/0003_krl_revision.d.ts +3 -0
  34. package/dist/db/migrations/0003_krl_revision.d.ts.map +1 -0
  35. package/dist/db/migrations/0003_krl_revision.js +14 -0
  36. package/dist/db/migrations/0003_krl_revision.js.map +1 -0
  37. package/dist/db/migrations/index.d.ts.map +1 -1
  38. package/dist/db/migrations/index.js +2 -0
  39. package/dist/db/migrations/index.js.map +1 -1
  40. package/dist/db/types.d.ts +2 -0
  41. package/dist/db/types.d.ts.map +1 -1
  42. package/dist/index.d.ts +5 -2
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +4 -2
  45. package/dist/index.js.map +1 -1
  46. package/dist/krl.d.ts +3 -2
  47. package/dist/krl.d.ts.map +1 -1
  48. package/dist/krl.js +12 -165
  49. package/dist/krl.js.map +1 -1
  50. package/dist/node/cache.d.ts +21 -0
  51. package/dist/node/cache.d.ts.map +1 -0
  52. package/dist/node/cache.js +49 -0
  53. package/dist/node/cache.js.map +1 -0
  54. package/dist/node/env.d.ts +6 -3
  55. package/dist/node/env.d.ts.map +1 -1
  56. package/dist/node/env.js +4 -3
  57. package/dist/node/env.js.map +1 -1
  58. package/dist/node/index.d.ts +1 -0
  59. package/dist/node/index.d.ts.map +1 -1
  60. package/dist/node/index.js +1 -0
  61. package/dist/node/index.js.map +1 -1
  62. package/dist/proof.d.ts +36 -7
  63. package/dist/proof.d.ts.map +1 -1
  64. package/dist/proof.js +53 -21
  65. package/dist/proof.js.map +1 -1
  66. package/dist/router.d.ts +25 -1
  67. package/dist/router.d.ts.map +1 -1
  68. package/dist/router.js +41 -2
  69. package/dist/router.js.map +1 -1
  70. package/dist/ssh/certificate.d.ts +93 -0
  71. package/dist/ssh/certificate.d.ts.map +1 -0
  72. package/dist/ssh/certificate.js +178 -0
  73. package/dist/ssh/certificate.js.map +1 -0
  74. package/dist/ssh/encoding.d.ts +41 -0
  75. package/dist/ssh/encoding.d.ts.map +1 -0
  76. package/dist/ssh/encoding.js +70 -0
  77. package/dist/ssh/encoding.js.map +1 -0
  78. package/dist/ssh/keys.d.ts +92 -0
  79. package/dist/ssh/keys.d.ts.map +1 -0
  80. package/dist/ssh/keys.js +277 -0
  81. package/dist/ssh/keys.js.map +1 -0
  82. package/dist/ssh/signer.d.ts +35 -0
  83. package/dist/ssh/signer.d.ts.map +1 -0
  84. package/dist/ssh/signer.js +99 -0
  85. package/dist/ssh/signer.js.map +1 -0
  86. package/dist/types.d.ts +64 -19
  87. package/dist/types.d.ts.map +1 -1
  88. package/dist/utils.d.ts +107 -21
  89. package/dist/utils.d.ts.map +1 -1
  90. package/dist/utils.js +251 -65
  91. package/dist/utils.js.map +1 -1
  92. package/dist/verify.d.ts +17 -5
  93. package/dist/verify.d.ts.map +1 -1
  94. package/dist/verify.js +47 -9
  95. package/dist/verify.js.map +1 -1
  96. package/openapi.json +1942 -1
  97. package/package.json +4 -3
  98. package/src/api/operations.ts +314 -0
  99. package/src/api/schema.ts +146 -0
  100. package/src/api/v3/index.ts +21 -248
  101. package/src/api/v3/schema.ts +36 -128
  102. package/src/api/v4/index.ts +266 -0
  103. package/src/api/v4/schema.ts +241 -0
  104. package/src/certificate.ts +62 -123
  105. package/src/db/index.ts +196 -56
  106. package/src/db/migrations/0003_krl_revision.ts +15 -0
  107. package/src/db/migrations/index.ts +2 -0
  108. package/src/db/types.ts +2 -0
  109. package/src/index.ts +6 -4
  110. package/src/krl.ts +13 -197
  111. package/src/node/cache.ts +62 -0
  112. package/src/node/env.ts +6 -5
  113. package/src/node/index.ts +1 -0
  114. package/src/proof.ts +65 -31
  115. package/src/router.ts +67 -3
  116. package/src/ssh/certificate.ts +236 -0
  117. package/src/ssh/encoding.ts +81 -0
  118. package/src/ssh/keys.ts +327 -0
  119. package/src/ssh/signer.ts +129 -0
  120. package/src/types.ts +60 -20
  121. package/src/utils.ts +285 -81
  122. package/src/verify.ts +54 -14
@@ -0,0 +1,178 @@
1
+ import * as P from "micro-packed";
2
+ import { decodePublicKey, PublicKeyFieldCounts, SSHBytes, SSHOptions, SSHText, SSHTextList, } from "./encoding.js";
3
+ import { base64 } from "@scure/base";
4
+ import { KeyParseError, PublicKey } from "./keys.js";
5
+ import { verify } from "./signer.js";
6
+ const CertificateKinds = {
7
+ user: 1,
8
+ host: 2,
9
+ };
10
+ // the fields of a certificate that follow its type, which are given the
11
+ // number of fields in the public key of the certificate
12
+ const fields = (keyFields) => ({
13
+ nonce: SSHBytes,
14
+ key: P.array(keyFields, SSHBytes),
15
+ serial: P.U64BE,
16
+ kind: P.U32BE,
17
+ keyId: SSHText,
18
+ principals: SSHTextList,
19
+ validAfter: P.U64BE,
20
+ validBefore: P.U64BE,
21
+ criticalOptions: SSHOptions,
22
+ extensions: SSHOptions,
23
+ reserved: SSHBytes,
24
+ signatureKey: SSHBytes,
25
+ });
26
+ const certificateType = (keyType) => `${keyType}-cert-v01@openssh.com`;
27
+ // a certificate without and with its signature, tagged by the certificate type
28
+ const ToBeSigned = P.tag(SSHText, Object.fromEntries(Object.entries(PublicKeyFieldCounts).map(([keyType, count]) => [certificateType(keyType), P.struct(fields(count))])));
29
+ const Certificate = P.tag(SSHText, Object.fromEntries(Object.entries(PublicKeyFieldCounts).map(([keyType, count]) => [certificateType(keyType), P.struct({ ...fields(count), signature: SSHBytes })])));
30
+ const toSeconds = (date) => BigInt(Math.floor(date.getTime() / 1000));
31
+ /**
32
+ * Thrown when a certificate cannot be parsed
33
+ */
34
+ export class CertificateParseError extends Error {
35
+ constructor(message, cause) {
36
+ super(message);
37
+ this.name = "CertificateParseError";
38
+ this.cause = cause;
39
+ Object.setPrototypeOf(this, CertificateParseError.prototype);
40
+ }
41
+ }
42
+ /**
43
+ * A signed OpenSSH certificate
44
+ */
45
+ export class SshCertificate {
46
+ /** The wire encoding of the certificate */
47
+ bytes;
48
+ /** The certificate type, for example "ssh-ed25519-cert-v01@openssh.com" */
49
+ type;
50
+ kind;
51
+ /** The public key being certified */
52
+ publicKey;
53
+ serial;
54
+ keyId;
55
+ principals;
56
+ validAfter;
57
+ validBefore;
58
+ /** The names of the extensions on the certificate */
59
+ extensions;
60
+ /** The wire encoding of the public key of the CA that signed the certificate */
61
+ signatureKey;
62
+ /** The signature of the CA in the SSH wire format */
63
+ signature;
64
+ /**
65
+ * Decodes a certificate from its wire encoding. This does not verify the
66
+ * signature on the certificate.
67
+ *
68
+ * @param bytes The wire encoding of the certificate
69
+ * @throws {@link CertificateParseError} when the certificate cannot be decoded or its type is not supported
70
+ */
71
+ constructor(bytes) {
72
+ let decoded;
73
+ try {
74
+ decoded = Certificate.decode(bytes);
75
+ }
76
+ catch (err) {
77
+ throw new CertificateParseError("certificate could not be decoded", err);
78
+ }
79
+ const { TAG, data } = decoded;
80
+ const kind = Object.keys(CertificateKinds).find((k) => CertificateKinds[k] === data.kind);
81
+ if (kind === undefined) {
82
+ throw new CertificateParseError(`unknown certificate kind: ${data.kind}`);
83
+ }
84
+ const publicKeyType = TAG.replace(/-cert-v01@openssh\.com$/, "");
85
+ try {
86
+ this.publicKey = new PublicKey(P.struct({ type: SSHText, key: P.array(data.key.length, SSHBytes) }).encode({ type: publicKeyType, key: data.key }));
87
+ }
88
+ catch (err) {
89
+ throw new CertificateParseError(err instanceof KeyParseError ? err.message : "certificate public key could not be decoded", err);
90
+ }
91
+ this.bytes = bytes;
92
+ this.type = TAG;
93
+ this.kind = kind;
94
+ this.serial = data.serial;
95
+ this.keyId = data.keyId;
96
+ this.principals = data.principals;
97
+ this.validAfter = new Date(Number(data.validAfter) * 1000);
98
+ this.validBefore = new Date(Number(data.validBefore) * 1000);
99
+ this.extensions = data.extensions.map((e) => e.name);
100
+ this.signatureKey = data.signatureKey;
101
+ this.signature = data.signature;
102
+ }
103
+ /**
104
+ * Parses a certificate in OpenSSH format, `${type} ${base64}[ ${comment}]`,
105
+ * as found in `-cert.pub` files. This does not verify the signature on the
106
+ * certificate.
107
+ *
108
+ * @param text The certificate
109
+ * @throws {@link CertificateParseError} when the certificate cannot be parsed or its type is not supported
110
+ */
111
+ static parse(text) {
112
+ const [type, data] = text.trim().split(/\s+/);
113
+ if (type === undefined || type === "" || data === undefined) {
114
+ throw new CertificateParseError("certificate was not in OpenSSH format");
115
+ }
116
+ let bytes;
117
+ try {
118
+ bytes = base64.decode(data);
119
+ }
120
+ catch (err) {
121
+ throw new CertificateParseError("certificate was not valid base64", err);
122
+ }
123
+ const certificate = new SshCertificate(bytes);
124
+ if (certificate.type !== type) {
125
+ throw new CertificateParseError(`certificate type ${type} did not match encoded type ${certificate.type}`);
126
+ }
127
+ return certificate;
128
+ }
129
+ /**
130
+ * Returns whether the certificate was signed by a CA key
131
+ *
132
+ * @param ca The public key of the CA
133
+ */
134
+ async isSignedBy(ca) {
135
+ if (!ca.equals(new PublicKey(this.signatureKey))) {
136
+ return false;
137
+ }
138
+ // the signature is the last field, so everything before it is signed
139
+ const signed = this.bytes.subarray(0, this.bytes.length - 4 - this.signature.length);
140
+ return await verify(ca, this.signature, new Uint8Array(signed));
141
+ }
142
+ /**
143
+ * Returns the certificate in OpenSSH format, as used for `-cert.pub` files
144
+ */
145
+ toString() {
146
+ return `${this.type} ${base64.encode(this.bytes)}`;
147
+ }
148
+ }
149
+ /**
150
+ * Creates and signs an OpenSSH certificate
151
+ *
152
+ * @param fields The fields of the certificate
153
+ * @param signer The CA key to sign the certificate with
154
+ * @returns The signed certificate
155
+ * @throws Error when the type of the public key being certified is not supported
156
+ */
157
+ export const signCertificate = async (fields, signer) => {
158
+ const { type, fields: key } = decodePublicKey(fields.publicKey.blob);
159
+ const value = {
160
+ nonce: crypto.getRandomValues(new Uint8Array(32)),
161
+ key,
162
+ serial: fields.serial,
163
+ kind: CertificateKinds[fields.kind],
164
+ keyId: fields.keyId,
165
+ principals: fields.principals,
166
+ validAfter: toSeconds(fields.validAfter),
167
+ validBefore: toSeconds(fields.validBefore),
168
+ criticalOptions: [],
169
+ // options must be in lexical order and may each appear only once
170
+ extensions: [...new Set(fields.extensions)].sort().map((name) => ({ name, data: new Uint8Array(0) })),
171
+ reserved: new Uint8Array(0),
172
+ signatureKey: signer.publicKey,
173
+ };
174
+ const tbs = ToBeSigned.encode({ TAG: certificateType(type), data: value });
175
+ const signature = await signer.sign(new Uint8Array(tbs));
176
+ return new SshCertificate(Certificate.encode({ TAG: certificateType(type), data: { ...value, signature } }));
177
+ };
178
+ //# sourceMappingURL=certificate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificate.js","sourceRoot":"","sources":["../../src/ssh/certificate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import * as P from "micro-packed";
2
+ /**
3
+ * Coders for the SSH wire format (RFC 4251 section 5)
4
+ */
5
+ /** A string of bytes, prefixed by its length as a uint32 */
6
+ export declare const SSHBytes: P.CoderType<P.Bytes>;
7
+ /** A UTF-8 string, prefixed by its length as a uint32 */
8
+ export declare const SSHText: P.CoderType<string>;
9
+ /** A list of strings packed into a string, as used for certificate principals */
10
+ export declare const SSHTextList: P.CoderType<string[]>;
11
+ /**
12
+ * A list of named options packed into a string, as used for certificate
13
+ * critical options and extensions
14
+ */
15
+ export declare const SSHOptions: P.CoderType<P.StructInput<{
16
+ name: string;
17
+ data: P.Bytes;
18
+ }>[]>;
19
+ /**
20
+ * An mpint holding an unsigned integer, decoded to and encoded from its
21
+ * big-endian bytes without leading zeros.
22
+ *
23
+ * An mpint has no leading zero bytes, other than one to keep the value
24
+ * positive when the high bit of the first byte is set.
25
+ */
26
+ export declare const SSHUnsignedMpint: P.CoderType<Uint8Array<ArrayBufferLike>>;
27
+ /** The number of fields that follow the type in the wire encoding of a public key of each type */
28
+ export declare const PublicKeyFieldCounts: Readonly<Record<string, number>>;
29
+ /**
30
+ * Splits the wire encoding of a public key into its type and the encoded
31
+ * fields that follow it
32
+ *
33
+ * @param blob The wire encoding of the public key
34
+ * @returns The key type and its fields
35
+ * @throws Error when the key type is not supported or the encoding is invalid
36
+ */
37
+ export declare const decodePublicKey: (blob: Uint8Array) => {
38
+ type: string;
39
+ fields: Uint8Array[];
40
+ };
41
+ //# sourceMappingURL=encoding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/ssh/encoding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAEjC;;GAEG;AAEH,4DAA4D;AAC5D,eAAO,MAAM,QAAQ,sBAAmB,CAAA;AAExC,yDAAyD;AACzD,eAAO,MAAM,OAAO,qBAAoB,CAAA;AAExC,iFAAiF;AACjF,eAAO,MAAM,WAAW,uBAA4C,CAAA;AAEpE;;;GAGG;AACH,eAAO,MAAM,UAAU;;;KAGnB,CAAA;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,0CAoB3B,CAAA;AAEF,kGAAkG;AAClG,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMjE,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,SAAU,UAAU,KAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAA;CAUtF,CAAA"}
@@ -0,0 +1,70 @@
1
+ import * as P from "micro-packed";
2
+ /**
3
+ * Coders for the SSH wire format (RFC 4251 section 5)
4
+ */
5
+ /** A string of bytes, prefixed by its length as a uint32 */
6
+ export const SSHBytes = P.bytes(P.U32BE);
7
+ /** A UTF-8 string, prefixed by its length as a uint32 */
8
+ export const SSHText = P.string(P.U32BE);
9
+ /** A list of strings packed into a string, as used for certificate principals */
10
+ export const SSHTextList = P.prefix(P.U32BE, P.array(null, SSHText));
11
+ /**
12
+ * A list of named options packed into a string, as used for certificate
13
+ * critical options and extensions
14
+ */
15
+ export const SSHOptions = P.prefix(P.U32BE, P.array(null, P.struct({
16
+ name: SSHText,
17
+ data: SSHBytes,
18
+ })));
19
+ /**
20
+ * An mpint holding an unsigned integer, decoded to and encoded from its
21
+ * big-endian bytes without leading zeros.
22
+ *
23
+ * An mpint has no leading zero bytes, other than one to keep the value
24
+ * positive when the high bit of the first byte is set.
25
+ */
26
+ export const SSHUnsignedMpint = P.apply(SSHBytes, {
27
+ encode: (mpint) => {
28
+ let start = 0;
29
+ while (start < mpint.length && mpint[start] === 0) {
30
+ start++;
31
+ }
32
+ return mpint.subarray(start);
33
+ },
34
+ decode: (value) => {
35
+ let start = 0;
36
+ while (start < value.length && value[start] === 0) {
37
+ start++;
38
+ }
39
+ const trimmed = value.subarray(start);
40
+ return trimmed.length > 0 && trimmed[0] & 0x80
41
+ ? P.utils.concatBytes(new Uint8Array([0]), trimmed)
42
+ : trimmed;
43
+ },
44
+ });
45
+ /** The number of fields that follow the type in the wire encoding of a public key of each type */
46
+ export const PublicKeyFieldCounts = {
47
+ "ssh-ed25519": 1, // public key
48
+ "ecdsa-sha2-nistp256": 2, // curve, public key
49
+ "ecdsa-sha2-nistp384": 2,
50
+ "ecdsa-sha2-nistp521": 2,
51
+ "ssh-rsa": 2, // e, n
52
+ };
53
+ /**
54
+ * Splits the wire encoding of a public key into its type and the encoded
55
+ * fields that follow it
56
+ *
57
+ * @param blob The wire encoding of the public key
58
+ * @returns The key type and its fields
59
+ * @throws Error when the key type is not supported or the encoding is invalid
60
+ */
61
+ export const decodePublicKey = (blob) => {
62
+ const type = SSHText.decode(blob, { allowUnreadBytes: true });
63
+ const count = PublicKeyFieldCounts[type];
64
+ if (count === undefined) {
65
+ throw new Error(`unsupported public key type: ${type}`);
66
+ }
67
+ const { fields } = P.struct({ type: SSHText, fields: P.array(count, SSHBytes) }).decode(blob);
68
+ return { type, fields };
69
+ };
70
+ //# sourceMappingURL=encoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../src/ssh/encoding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Thrown when a key cannot be parsed
3
+ */
4
+ export declare class KeyParseError extends Error {
5
+ constructor(message: string, cause?: unknown);
6
+ }
7
+ /**
8
+ * Thrown when a private key is of a type that cannot be used to sign
9
+ */
10
+ export declare class UnsupportedKeyError extends Error {
11
+ constructor(message: string);
12
+ }
13
+ /**
14
+ * An SSH public key
15
+ */
16
+ export declare class PublicKey {
17
+ /** The key type, for example "ssh-ed25519" */
18
+ readonly type: string;
19
+ /** The wire encoding of the key (RFC 4253 section 6.6) */
20
+ readonly blob: Uint8Array;
21
+ /** The comment of the key, if any */
22
+ readonly comment: string | undefined;
23
+ /**
24
+ * @param blob The wire encoding of the key
25
+ * @param comment The comment of the key
26
+ * @throws {@link KeyParseError} when the key cannot be decoded or its type is not supported
27
+ */
28
+ constructor(blob: Uint8Array, comment?: string);
29
+ /**
30
+ * Parses a public key in OpenSSH format, `${type} ${base64}[ ${comment}]`
31
+ *
32
+ * @param text The public key
33
+ * @throws {@link KeyParseError} when the key cannot be parsed or its type is not supported
34
+ */
35
+ static parse(text: string): PublicKey;
36
+ /**
37
+ * Returns the SHA256 fingerprint of the key, as shown by `ssh-keygen -l`,
38
+ * for example "SHA256:79mq0wtpQMTvS4+Of8VzLN0qmYWNUyTXYmqKwhEgSLs"
39
+ */
40
+ fingerprint(): string;
41
+ /**
42
+ * Returns whether this is the same key as another, ignoring comments
43
+ */
44
+ equals(other: PublicKey): boolean;
45
+ /**
46
+ * Returns a copy of the key with a different comment
47
+ */
48
+ withComment(comment: string | undefined): PublicKey;
49
+ /**
50
+ * Returns the key in OpenSSH format, `${type} ${base64}[ ${comment}]`
51
+ */
52
+ toString(): string;
53
+ }
54
+ /**
55
+ * The smallest RSA key, in bits, that the CA will issue a certificate for.
56
+ * This matches the minimum accepted by ssh-ca-client.
57
+ */
58
+ export declare const MinimumRsaKeyBits = 2048;
59
+ /**
60
+ * Returns the size in bits of the modulus of an RSA public key, or undefined
61
+ * if the key is not an RSA key.
62
+ *
63
+ * @param key The public key
64
+ */
65
+ export declare const rsaKeyBits: (key: PublicKey) => number | undefined;
66
+ /** The ECDSA curves that can be used to sign */
67
+ export type EcdsaCurve = "nistp256" | "nistp384" | "nistp521";
68
+ /**
69
+ * A private key that can be used to sign, with its key material as a JWK for
70
+ * WebCrypto
71
+ */
72
+ export type PrivateKey = {
73
+ readonly type: "ed25519";
74
+ readonly publicKey: PublicKey;
75
+ readonly jwk: JsonWebKey;
76
+ } | {
77
+ readonly type: "ecdsa";
78
+ readonly curve: EcdsaCurve;
79
+ readonly publicKey: PublicKey;
80
+ readonly jwk: JsonWebKey;
81
+ };
82
+ /**
83
+ * Parses an unencrypted Ed25519 or ECDSA private key in OpenSSH format, as
84
+ * created by `ssh-keygen`
85
+ *
86
+ * @param text The private key, starting with `-----BEGIN OPENSSH PRIVATE KEY-----`
87
+ * @returns The private key
88
+ * @throws {@link KeyParseError} when the key cannot be parsed or is encrypted
89
+ * @throws {@link UnsupportedKeyError} when the key is not an Ed25519 or ECDSA key
90
+ */
91
+ export declare const parsePrivateKey: (text: string) => PrivateKey;
92
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/ssh/keys.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACvC,YAAY,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAM3C;CACD;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC7C,YAAY,OAAO,EAAE,MAAM,EAK1B;CACD;AAMD;;GAEG;AACH,qBAAa,SAAS;IACrB,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAEpC;;;;OAIG;IACH,YAAY,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,MAAM,EAQ7C;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAmBpC;IAED;;;OAGG;IACH,WAAW,IAAI,MAAM,CAEpB;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEhC;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAElD;IAED;;OAEG;IACH,QAAQ,IAAI,MAAM,CAIjB;CACD;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC;;;;;GAKG;AACH,eAAO,MAAM,UAAU,QAAS,SAAS,KAAG,MAAM,GAAG,SAmBpD,CAAA;AAED,gDAAgD;AAChD,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAA;AAQ7D;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CACxB,GAAG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CACxB,CAAA;AAkDD;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,SAAU,MAAM,KAAG,UA2F9C,CAAA"}