@particle/esim-tooling 1.0.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 (77) hide show
  1. package/README.md +187 -0
  2. package/dist/activation-code.d.ts +11 -0
  3. package/dist/activation-code.d.ts.map +1 -0
  4. package/dist/activation-code.js +56 -0
  5. package/dist/activation-code.js.map +1 -0
  6. package/dist/apdu.d.ts +73 -0
  7. package/dist/apdu.d.ts.map +1 -0
  8. package/dist/apdu.js +357 -0
  9. package/dist/apdu.js.map +1 -0
  10. package/dist/errors.d.ts +32 -0
  11. package/dist/errors.d.ts.map +1 -0
  12. package/dist/errors.js +52 -0
  13. package/dist/errors.js.map +1 -0
  14. package/dist/es10/es10b-notifications.d.ts +30 -0
  15. package/dist/es10/es10b-notifications.d.ts.map +1 -0
  16. package/dist/es10/es10b-notifications.js +294 -0
  17. package/dist/es10/es10b-notifications.js.map +1 -0
  18. package/dist/es10/es10b.d.ts +34 -0
  19. package/dist/es10/es10b.d.ts.map +1 -0
  20. package/dist/es10/es10b.js +108 -0
  21. package/dist/es10/es10b.js.map +1 -0
  22. package/dist/es10/es10c.d.ts +12 -0
  23. package/dist/es10/es10c.d.ts.map +1 -0
  24. package/dist/es10/es10c.js +133 -0
  25. package/dist/es10/es10c.js.map +1 -0
  26. package/dist/es10/iccid.d.ts +9 -0
  27. package/dist/es10/iccid.d.ts.map +1 -0
  28. package/dist/es10/iccid.js +31 -0
  29. package/dist/es10/iccid.js.map +1 -0
  30. package/dist/es10/index.d.ts +5 -0
  31. package/dist/es10/index.d.ts.map +1 -0
  32. package/dist/es10/index.js +4 -0
  33. package/dist/es10/index.js.map +1 -0
  34. package/dist/es10/tags.d.ts +55 -0
  35. package/dist/es10/tags.d.ts.map +1 -0
  36. package/dist/es10/tags.js +63 -0
  37. package/dist/es10/tags.js.map +1 -0
  38. package/dist/es9plus.d.ts +52 -0
  39. package/dist/es9plus.d.ts.map +1 -0
  40. package/dist/es9plus.js +227 -0
  41. package/dist/es9plus.js.map +1 -0
  42. package/dist/gsma-rsp2-root-ci1.d.ts +38 -0
  43. package/dist/gsma-rsp2-root-ci1.d.ts.map +1 -0
  44. package/dist/gsma-rsp2-root-ci1.js +52 -0
  45. package/dist/gsma-rsp2-root-ci1.js.map +1 -0
  46. package/dist/index.d.ts +6 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +5 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/lpa.d.ts +15 -0
  51. package/dist/lpa.d.ts.map +1 -0
  52. package/dist/lpa.js +283 -0
  53. package/dist/lpa.js.map +1 -0
  54. package/dist/tlv.d.ts +14 -0
  55. package/dist/tlv.d.ts.map +1 -0
  56. package/dist/tlv.js +132 -0
  57. package/dist/tlv.js.map +1 -0
  58. package/dist/types.d.ts +230 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +108 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +50 -0
  63. package/src/activation-code.ts +64 -0
  64. package/src/apdu.ts +419 -0
  65. package/src/errors.ts +69 -0
  66. package/src/es10/es10b-notifications.ts +331 -0
  67. package/src/es10/es10b.ts +163 -0
  68. package/src/es10/es10c.ts +168 -0
  69. package/src/es10/iccid.ts +32 -0
  70. package/src/es10/index.ts +42 -0
  71. package/src/es10/tags.ts +69 -0
  72. package/src/es9plus.ts +331 -0
  73. package/src/gsma-rsp2-root-ci1.ts +53 -0
  74. package/src/index.ts +43 -0
  75. package/src/lpa.ts +346 -0
  76. package/src/tlv.ts +137 -0
  77. package/src/types.ts +264 -0
@@ -0,0 +1,42 @@
1
+ export {
2
+ encodeGetEidRequest,
3
+ decodeGetEidResponse,
4
+ encodeGetProfilesInfoRequest,
5
+ decodeGetProfilesInfoResponse,
6
+ encodeEnableProfileRequest,
7
+ decodeEnableProfileResponse,
8
+ encodeDisableProfileRequest,
9
+ decodeDisableProfileResponse,
10
+ encodeDeleteProfileRequest,
11
+ decodeDeleteProfileResponse,
12
+ } from './es10c.js';
13
+
14
+ export {
15
+ encodeGetEuiccChallengeRequest,
16
+ decodeGetEuiccChallengeResponse,
17
+ encodeGetEuiccInfo1Request,
18
+ encodeAuthenticateServerRequest,
19
+ decodeAuthenticateServerResponse,
20
+ encodePrepareDownloadRequest,
21
+ decodePrepareDownloadResponse,
22
+ hashConfirmationCode,
23
+ encodeCancelSessionRequest,
24
+ } from './es10b.js';
25
+
26
+ export type {
27
+ AuthenticateServerParams,
28
+ PrepareDownloadParams,
29
+ AuthenticateServerDecodedResponse,
30
+ PrepareDownloadDecodedResponse,
31
+ } from './es10b.js';
32
+
33
+ export {
34
+ encodeListNotificationRequest,
35
+ decodeListNotificationResponse,
36
+ encodeRetrieveNotificationsListRequest,
37
+ decodeRetrieveNotificationsListResponse,
38
+ decodeRetrieveNotificationsListFull,
39
+ decodeBppInstallationResult,
40
+ encodeRemoveNotificationRequest,
41
+ decodeRemoveNotificationResponse,
42
+ } from './es10b-notifications.js';
@@ -0,0 +1,69 @@
1
+ // ES10c - Profile Management
2
+ export const TAG_PROFILE_INFO_LIST_REQUEST = 0xbf2d;
3
+ export const TAG_PROFILE_INFO = 0xe3;
4
+ export const TAG_ICCID = 0x5a;
5
+ export const TAG_ISDP_AID = 0x4f;
6
+ export const TAG_PROFILE_STATE = 0x9f70;
7
+ export const TAG_PROFILE_NICKNAME = 0x90;
8
+ export const TAG_SERVICE_PROVIDER_NAME = 0x91;
9
+ export const TAG_PROFILE_NAME = 0x92;
10
+ export const TAG_PROFILE_CLASS = 0x95;
11
+ export const TAG_TAG_LIST = 0x5c;
12
+ export const TAG_GET_EID_REQUEST = 0xbf3e;
13
+ export const TAG_EID = 0x5a;
14
+ export const TAG_ENABLE_PROFILE_REQUEST = 0xbf31;
15
+ export const TAG_DISABLE_PROFILE_REQUEST = 0xbf32;
16
+ export const TAG_DELETE_PROFILE_REQUEST = 0xbf33;
17
+ export const TAG_PROFILE_IDENTIFIER = 0xa0;
18
+ export const TAG_REFRESH_FLAG = 0x81;
19
+ export const TAG_RESULT = 0x80;
20
+
21
+ // ES10b - Profile Download
22
+ export const TAG_GET_EUICC_CHALLENGE_REQUEST = 0xbf2e;
23
+ export const TAG_EUICC_CHALLENGE = 0x80;
24
+ export const TAG_GET_EUICC_INFO1_REQUEST = 0xbf20;
25
+ export const TAG_AUTHENTICATE_SERVER_REQUEST = 0xbf38;
26
+ export const TAG_CTX_PARAMS1 = 0xa0;
27
+ export const TAG_MATCHING_ID = 0x80;
28
+ export const TAG_DEVICE_INFO = 0xa1;
29
+ export const TAG_PREPARE_DOWNLOAD_REQUEST = 0xbf21;
30
+ export const TAG_HASH_CC = 0x04;
31
+ export const TAG_EUICC_SIGNATURE1 = 0x5f37;
32
+ export const TAG_CANCEL_SESSION_REQUEST = 0xbf41;
33
+ export const TAG_CANCEL_SESSION_REASON = 0x80;
34
+ export const TAG_CANCEL_SESSION_TRANSACTION_ID = 0x80;
35
+
36
+ // ES10b - BPP Loading
37
+ export const TAG_BOUND_PROFILE_PACKAGE = 0xbf36;
38
+
39
+ // ES10b - Notifications
40
+ export const TAG_LIST_NOTIFICATION_REQUEST = 0xbf28;
41
+ export const TAG_NOTIFICATION_METADATA_LIST = 0xa0;
42
+ export const TAG_NOTIFICATION_METADATA = 0xbf2f;
43
+ export const TAG_NOTIFICATION_SEQ_NUMBER = 0x80;
44
+ export const TAG_NOTIFICATION_OPERATION = 0x81;
45
+ export const TAG_NOTIFICATION_ADDRESS = 0x0c;
46
+ export const TAG_NOTIFICATION_ICCID = 0x5a;
47
+ export const TAG_RETRIEVE_NOTIFICATIONS_LIST_REQUEST = 0xbf2b;
48
+ export const TAG_NOTIFICATION_SEARCH_CRITERIA = 0xa0;
49
+ export const TAG_REMOVE_NOTIFICATION_REQUEST = 0xbf30;
50
+ export const TAG_DELETE_NOTIFICATION_STATUS = 0x80;
51
+
52
+ // ES10b - ProfileInstallationResult (in notifications and BPP response)
53
+ export const TAG_PROFILE_INSTALLATION_RESULT = 0xbf37;
54
+ export const TAG_PROFILE_INSTALLATION_RESULT_DATA = 0xbf27;
55
+ export const TAG_FINAL_RESULT = 0xa2; // success - contains ICCID
56
+ export const TAG_ERROR_RESULT = 0xa1; // failure - contains subjectCode + reasonCode
57
+ export const TAG_SUBJECT_CODE = 0x80;
58
+ export const TAG_REASON_CODE = 0x81;
59
+
60
+ // ES10b - OtherSignedNotification (SEQUENCE tag)
61
+ export const TAG_OTHER_SIGNED_NOTIFICATION = 0x30;
62
+
63
+ // ES10b - AuthenticateServer response
64
+ export const TAG_AUTH_SERVER_RESPONSE_OK = 0xa0;
65
+ export const TAG_AUTH_SERVER_RESPONSE_ERROR = 0xa1;
66
+
67
+ // ES10b - PrepareDownload response
68
+ export const TAG_PREPARE_DOWNLOAD_RESPONSE_OK = 0xa0;
69
+ export const TAG_PREPARE_DOWNLOAD_RESPONSE_ERROR = 0xa1;
package/src/es9plus.ts ADDED
@@ -0,0 +1,331 @@
1
+ import { Es9PlusError } from './errors.js';
2
+ import type { ServerAdapter } from './types.js';
3
+ import { tlvEncode, tlvDecode, tlvConcat, type TlvNode } from './tlv.js';
4
+ import { decodeIccid } from './es10/iccid.js';
5
+
6
+ // ES9+ operation tags (SGP.22 ASN.1)
7
+ const TAG_REMOTE_PROFILE_PROVISIONING = 0xa2; // [2] RemoteProfileProvisioningRequest/Response wrapper (SGP.22 6.6.1)
8
+ const TAG_INITIATE_AUTH = 0xbf39; // [57] InitiateAuthenticationRequest/Response
9
+ const TAG_GET_BPP = 0xbf3a; // [58] GetBoundProfilePackageRequest/Response
10
+ const TAG_AUTHENTICATE_CLIENT = 0xbf3b; // [59] AuthenticateClientRequest/Response
11
+ const TAG_HANDLE_NOTIFICATION = 0xbf3d; // [61] HandleNotification
12
+ const TAG_CANCEL_SESSION = 0xbf41; // [65] CancelSessionRequestEs9/Response
13
+
14
+ // Common ASN.1 tags
15
+ const TAG_OCTET_STRING = 0x04;
16
+
17
+ // ES9+ CHOICE response tags (AUTOMATIC TAGS → implicit context tags)
18
+ // Success variants are context [0], error INTEGER is context [1]
19
+ const TAG_RESPONSE_OK = 0xa0; // [0] IMPLICIT SEQUENCE (constructed)
20
+ const TAG_RESPONSE_ERROR = 0x81; // [1] IMPLICIT INTEGER (primitive)
21
+
22
+ // ES9+ error code names (SGP.22 Section 6.5.2)
23
+ const ES9PLUS_ERROR_NAMES: Record<number, string> = {
24
+ 1: 'eumCertificateInvalid',
25
+ 2: 'eumCertificateExpired',
26
+ 3: 'euiccCertificateInvalid',
27
+ 4: 'euiccCertificateExpired',
28
+ 5: 'euiccSignatureInvalid',
29
+ 6: 'matchingIdRefused',
30
+ 7: 'eidMismatch',
31
+ 8: 'noEligibleProfile',
32
+ 9: 'ciPKUnknown',
33
+ 10: 'invalidTransactionId',
34
+ 11: 'insufficientMemory',
35
+ 12: 'ciPKMismatch',
36
+ 127: 'undefinedError',
37
+ };
38
+
39
+ // Context tags for IMPLICIT fields in ES9+ SEQUENCE members
40
+ const TAG_TRANSACTION_ID = 0x80; // [0] TransactionId (OCTET STRING)
41
+ const TAG_EUICC_CHALLENGE = 0x81; // [1] Octet16
42
+ const TAG_SMDP_ADDRESS = 0x83; // [3] UTF8String
43
+
44
+ // Tags inside StoreMetadataRequest (profileMetadata)
45
+ const TAG_ICCID = 0x5a; // [APPLICATION 26] ICCID
46
+ const TAG_PROFILE_METADATA = 0xbf25; // [37] StoreMetadataRequest
47
+ const TAG_SERVICE_PROVIDER_NAME = 0x91; // [17] UTF8String
48
+ const TAG_PROFILE_NAME = 0x92; // [18] UTF8String
49
+
50
+ export interface InitiateAuthParams {
51
+ euiccChallenge: Uint8Array;
52
+ euiccInfo1: Uint8Array;
53
+ }
54
+
55
+ export interface InitiateAuthResponse {
56
+ transactionId: string;
57
+ serverSigned1: Uint8Array;
58
+ serverSignature1: Uint8Array;
59
+ euiccCiPKIdToBeUsed: Uint8Array;
60
+ serverCertificate: Uint8Array;
61
+ }
62
+
63
+ export interface AuthenticateClientParams {
64
+ transactionId: string;
65
+ authenticateServerResponse: Uint8Array;
66
+ }
67
+
68
+ export interface AuthenticateClientResponse {
69
+ transactionId: string;
70
+ smdpSigned2: Uint8Array;
71
+ smdpSignature2: Uint8Array;
72
+ smdpCertificate: Uint8Array;
73
+ profileMetadata?: ProfileMetadata;
74
+ }
75
+
76
+ export interface ProfileMetadata {
77
+ iccid?: string;
78
+ serviceProviderName?: string;
79
+ profileName?: string;
80
+ }
81
+
82
+ export interface GetBppParams {
83
+ transactionId: string;
84
+ prepareDownloadResponse: Uint8Array;
85
+ }
86
+
87
+ export interface GetBppResponse {
88
+ transactionId: string;
89
+ boundProfilePackage: Uint8Array;
90
+ }
91
+
92
+ export class Es9PlusClient {
93
+ private server: ServerAdapter;
94
+
95
+ constructor(server: ServerAdapter) {
96
+ this.server = server;
97
+ }
98
+
99
+ async initiateAuthentication(smdpAddress: string, params: InitiateAuthParams): Promise<InitiateAuthResponse> {
100
+ const body = tlvConcat(
101
+ tlvEncode(TAG_EUICC_CHALLENGE, params.euiccChallenge),
102
+ tlvEncode(TAG_SMDP_ADDRESS, new TextEncoder().encode(smdpAddress)),
103
+ params.euiccInfo1, // already DER-encoded with BF20 tag
104
+ );
105
+ const requestData = tlvEncode(TAG_INITIATE_AUTH, body);
106
+
107
+ const responseData = await this.sendRequest(smdpAddress, 'initiateAuthentication', requestData);
108
+ const outer = tlvDecode(responseData);
109
+ this.expectTag(outer, TAG_INITIATE_AUTH, 'initiateAuthentication');
110
+
111
+ const inner = this.getFirstChild(outer, 'initiateAuthentication');
112
+ if (inner.tag === TAG_RESPONSE_ERROR) {
113
+ throw this.makeError('initiateAuthentication', inner.value);
114
+ }
115
+
116
+ // Success SEQUENCE: [0]txId, ServerSigned1, 5F37 sig, 04 ciPKId, Certificate
117
+ const children = this.expectChildren(inner, 5, 'initiateAuthentication');
118
+
119
+ return {
120
+ transactionId: bytesToHex(children[0].value),
121
+ serverSigned1: children[1].raw!,
122
+ serverSignature1: children[2].raw!,
123
+ euiccCiPKIdToBeUsed: children[3].raw!,
124
+ serverCertificate: children[4].raw!,
125
+ };
126
+ }
127
+
128
+ async authenticateClient(smdpAddress: string, params: AuthenticateClientParams): Promise<AuthenticateClientResponse> {
129
+ const body = tlvConcat(
130
+ tlvEncode(TAG_TRANSACTION_ID, hexToBytes(params.transactionId)),
131
+ params.authenticateServerResponse, // already DER-encoded with BF38 tag
132
+ );
133
+ const requestData = tlvEncode(TAG_AUTHENTICATE_CLIENT, body);
134
+
135
+ const responseData = await this.sendRequest(smdpAddress, 'authenticateClient', requestData);
136
+ const outer = tlvDecode(responseData);
137
+ this.expectTag(outer, TAG_AUTHENTICATE_CLIENT, 'authenticateClient');
138
+
139
+ const inner = this.getFirstChild(outer, 'authenticateClient');
140
+ if (inner.tag === TAG_RESPONSE_ERROR) {
141
+ throw this.makeError('authenticateClient', inner.value);
142
+ }
143
+
144
+ // Success SEQUENCE: [0]txId, [37]profileMetadata?, SmdpSigned2, 5F37 sig, Certificate
145
+ const children = inner.children;
146
+ if (!children || children.length < 4) {
147
+ throw new Es9PlusError({ statusCode: 200, message: 'Incomplete authenticateClient response' });
148
+ }
149
+
150
+ let idx = 0;
151
+ const txId = bytesToHex(children[idx++].value);
152
+
153
+ let profileMetadata: ProfileMetadata | undefined;
154
+ if (idx < children.length && children[idx].tag === TAG_PROFILE_METADATA) {
155
+ profileMetadata = this.parseProfileMetadata(children[idx]);
156
+ idx++;
157
+ }
158
+
159
+ if (idx + 3 > children.length) {
160
+ throw new Es9PlusError({ statusCode: 200, message: 'Incomplete authenticateClient response' });
161
+ }
162
+
163
+ return {
164
+ transactionId: txId,
165
+ smdpSigned2: children[idx].raw!,
166
+ smdpSignature2: children[idx + 1].raw!,
167
+ smdpCertificate: children[idx + 2].raw!,
168
+ profileMetadata,
169
+ };
170
+ }
171
+
172
+ async getBoundProfilePackage(smdpAddress: string, params: GetBppParams): Promise<GetBppResponse> {
173
+ const body = tlvConcat(
174
+ tlvEncode(TAG_TRANSACTION_ID, hexToBytes(params.transactionId)),
175
+ params.prepareDownloadResponse, // already DER-encoded with BF21 tag
176
+ );
177
+ const requestData = tlvEncode(TAG_GET_BPP, body);
178
+
179
+ const responseData = await this.sendRequest(smdpAddress, 'getBoundProfilePackage', requestData);
180
+ const outer = tlvDecode(responseData);
181
+ this.expectTag(outer, TAG_GET_BPP, 'getBoundProfilePackage');
182
+
183
+ const inner = this.getFirstChild(outer, 'getBoundProfilePackage');
184
+ if (inner.tag === TAG_RESPONSE_ERROR) {
185
+ throw this.makeError('getBoundProfilePackage', inner.value);
186
+ }
187
+
188
+ // Success SEQUENCE: [0]txId, BF36{bpp}
189
+ const children = this.expectChildren(inner, 2, 'getBoundProfilePackage');
190
+
191
+ return {
192
+ transactionId: bytesToHex(children[0].value),
193
+ boundProfilePackage: children[1].raw!,
194
+ };
195
+ }
196
+
197
+ async handleNotification(notificationAddress: string, pendingNotification: Uint8Array): Promise<void> {
198
+ // BF3D { pendingNotification }, wrapped in A2 per SGP.22 Section 6.6.1
199
+ const innerRequest = tlvEncode(TAG_HANDLE_NOTIFICATION, pendingNotification);
200
+ const requestData = tlvEncode(TAG_REMOTE_PROFILE_PROVISIONING, innerRequest);
201
+
202
+ const response = await this.server.sendRsp(
203
+ notificationAddress,
204
+ 'handleNotification',
205
+ requestData,
206
+ );
207
+
208
+ if (response.statusCode === 204) return;
209
+
210
+ if (response.statusCode !== 200) {
211
+ throw new Es9PlusError({
212
+ statusCode: response.statusCode,
213
+ message: `handleNotification failed: HTTP ${response.statusCode}`,
214
+ });
215
+ }
216
+ }
217
+
218
+ async cancelSession(smdpAddress: string, transactionId: string, cancelSessionResponse: Uint8Array): Promise<void> {
219
+ // CancelSessionRequestEs9: transactionId has no context tag, uses native OCTET STRING
220
+ const body = tlvConcat(
221
+ tlvEncode(TAG_OCTET_STRING, hexToBytes(transactionId)),
222
+ cancelSessionResponse, // already DER-encoded with BF41 tag
223
+ );
224
+ const requestData = tlvEncode(TAG_CANCEL_SESSION, body);
225
+
226
+ await this.sendRequest(smdpAddress, 'cancelSession', requestData);
227
+ }
228
+
229
+ private async sendRequest(smdpAddress: string, endpoint: string, requestData: Uint8Array): Promise<Uint8Array> {
230
+ // Wrap request in RemoteProfileProvisioningRequest (A2) per SGP.22 Section 6.6.1
231
+ const wrappedRequest = tlvEncode(TAG_REMOTE_PROFILE_PROVISIONING, requestData);
232
+
233
+ const response = await this.server.sendRsp(smdpAddress, endpoint, wrappedRequest);
234
+
235
+ if (response.statusCode !== 200) {
236
+ throw new Es9PlusError({
237
+ statusCode: response.statusCode,
238
+ message: `${endpoint} failed: HTTP ${response.statusCode}`,
239
+ });
240
+ }
241
+
242
+ if (!response.responseData || response.responseData.length === 0) {
243
+ throw new Es9PlusError({
244
+ statusCode: response.statusCode,
245
+ message: `${endpoint} returned empty response`,
246
+ });
247
+ }
248
+
249
+ // Unwrap RemoteProfileProvisioningResponse (A2) wrapper per SGP.22 Section 6.6.1
250
+ const wrapper = tlvDecode(response.responseData);
251
+ this.expectTag(wrapper, TAG_REMOTE_PROFILE_PROVISIONING, endpoint);
252
+
253
+ // Return the raw bytes of the inner CHOICE element
254
+ const inner = this.getFirstChild(wrapper, endpoint);
255
+ return inner.raw!;
256
+ }
257
+
258
+ private expectTag(node: TlvNode, tag: number, operation: string): void {
259
+ if (node.tag !== tag) {
260
+ throw new Es9PlusError({
261
+ statusCode: 200,
262
+ message: `${operation}: unexpected response tag 0x${node.tag.toString(16)}`,
263
+ });
264
+ }
265
+ }
266
+
267
+ private getFirstChild(node: TlvNode, operation: string): TlvNode {
268
+ const inner = node.children?.[0];
269
+ if (!inner) {
270
+ throw new Es9PlusError({ statusCode: 200, message: `${operation}: empty response` });
271
+ }
272
+ return inner;
273
+ }
274
+
275
+ private expectChildren(node: TlvNode, minCount: number, operation: string): TlvNode[] {
276
+ const children = node.children;
277
+ if (!children || children.length < minCount) {
278
+ throw new Es9PlusError({
279
+ statusCode: 200,
280
+ message: `${operation}: incomplete response (expected ${minCount} fields, got ${children?.length ?? 0})`,
281
+ });
282
+ }
283
+ return children;
284
+ }
285
+
286
+ private parseProfileMetadata(node: TlvNode): ProfileMetadata {
287
+ const result: ProfileMetadata = {};
288
+ if (!node.children) return result;
289
+
290
+ for (const child of node.children) {
291
+ switch (child.tag) {
292
+ case TAG_ICCID:
293
+ result.iccid = decodeIccid(child.value);
294
+ break;
295
+ case TAG_SERVICE_PROVIDER_NAME:
296
+ result.serviceProviderName = new TextDecoder().decode(child.value);
297
+ break;
298
+ case TAG_PROFILE_NAME:
299
+ result.profileName = new TextDecoder().decode(child.value);
300
+ break;
301
+ }
302
+ }
303
+
304
+ return result;
305
+ }
306
+
307
+ private makeError(operation: string, errorValue: Uint8Array): Es9PlusError {
308
+ const code = errorValue.length > 0 ? errorValue[0] : 0;
309
+ const name = ES9PLUS_ERROR_NAMES[code] ?? `code ${code}`;
310
+ return new Es9PlusError({
311
+ statusCode: 200,
312
+ serverStatus: 'Failed',
313
+ reasonCode: String(code),
314
+ message: `${operation} failed: ${name}`,
315
+ });
316
+ }
317
+ }
318
+
319
+ function hexToBytes(hex: string): Uint8Array {
320
+ const bytes = new Uint8Array(hex.length / 2);
321
+ for (let i = 0; i < hex.length; i += 2) {
322
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
323
+ }
324
+ return bytes;
325
+ }
326
+
327
+ function bytesToHex(bytes: Uint8Array): string {
328
+ return Array.from(bytes)
329
+ .map((b) => b.toString(16).padStart(2, '0'))
330
+ .join('');
331
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * GSMA RSP2 Root CI1 Certificate
3
+ *
4
+ * This is the root Certificate Issuer (CI) for the GSMA Remote SIM Provisioning
5
+ * (RSP) ecosystem. It is used to:
6
+ *
7
+ * 1. Sign TLS certificates for SM-DP+ servers (enabling secure HTTPS connections)
8
+ * 2. Sign the SGP.22 PKI chain (EUM certificates, eUICC certificates)
9
+ *
10
+ * Certificate Details:
11
+ * - Subject: O=GSM Association, CN=GSM Association - RSP2 Root CI1
12
+ * - Issuer: Self-signed (same as subject)
13
+ * - Validity: Feb 22, 2017 - Feb 21, 2052
14
+ * - Subject Key ID: 81:37:0F:51:25:D0:B1:D4:08:D4:C3:B2:32:E6:D2:5E:79:5B:EB:FB
15
+ * - Algorithm: ECDSA with SHA-256 (P-256 curve)
16
+ *
17
+ * This certificate is NOT included in standard OS/browser CA stores because it's
18
+ * a private PKI specific to the GSMA eSIM ecosystem. Embedding it here allows
19
+ * the proxy to securely connect to SM-DP+ servers without disabling TLS verification.
20
+ *
21
+ * Source: Extracted from SM-DP+ server certificate chain
22
+ * Verified against: SGP.22 v2.2.2 Annex A, GSMA CI documentation
23
+ *
24
+ * @see https://www.gsma.com/esim/
25
+ * @see SGP.22 Section 4.1.1 (Certificate Issuer)
26
+ */
27
+ export const GSMA_RSP2_ROOT_CI1_PEM = `-----BEGIN CERTIFICATE-----
28
+ MIICSTCCAe+gAwIBAgIQbmhWeneg7nyF7hg5Y9+qejAKBggqhkjOPQQDAjBEMRgw
29
+ FgYDVQQKEw9HU00gQXNzb2NpYXRpb24xKDAmBgNVBAMTH0dTTSBBc3NvY2lhdGlv
30
+ biAtIFJTUDIgUm9vdCBDSTEwIBcNMTcwMjIyMDAwMDAwWhgPMjA1MjAyMjEyMzU5
31
+ NTlaMEQxGDAWBgNVBAoTD0dTTSBBc3NvY2lhdGlvbjEoMCYGA1UEAxMfR1NNIEFz
32
+ c29jaWF0aW9uIC0gUlNQMiBSb290IENJMTBZMBMGByqGSM49AgEGCCqGSM49AwEH
33
+ A0IABJ1qutL0HCMX52GJ6/jeibsAqZfULWj/X10p/Min6seZN+hf5llovbCNuB2n
34
+ unLz+O8UD0SUCBUVo8e6n9X1TuajgcAwgb0wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
35
+ EwEB/wQFMAMBAf8wEwYDVR0RBAwwCogIKwYBBAGC6WAwFwYDVR0gAQH/BA0wCzAJ
36
+ BgdngRIBAgEAME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9nc21hLWNybC5zeW1h
37
+ dXRoLmNvbS9vZmZsaW5lY2EvZ3NtYS1yc3AyLXJvb3QtY2kxLmNybDAdBgNVHQ4E
38
+ FgQUgTcPUSXQsdQI1MOyMubSXnlb6/swCgYIKoZIzj0EAwIDSAAwRQIgIJdYsOMF
39
+ WziPK7l8nh5mu0qiRiVf25oa9ullG/OIASwCIQDqCmDrYf+GziHXBOiwJwnBaeBO
40
+ aFsiLzIEOaUuZwdNUw==
41
+ -----END CERTIFICATE-----`;
42
+
43
+ /**
44
+ * Subject Key Identifier for GSMA RSP2 Root CI1
45
+ * This can be used to verify that an eUICC trusts this CI
46
+ * (appears in euiccInfo1.euiccCiPKIdListForVerification)
47
+ */
48
+ export const GSMA_RSP2_ROOT_CI1_SKI = '81370F5125D0B1D408D4C3B232E6D25E795BEBFB';
49
+
50
+ /**
51
+ * Common Name of the GSMA RSP2 Root CI1
52
+ */
53
+ export const GSMA_RSP2_ROOT_CI1_CN = 'GSM Association - RSP2 Root CI1';
package/src/index.ts ADDED
@@ -0,0 +1,43 @@
1
+ export { EsimLpa } from './lpa.js';
2
+
3
+ export {
4
+ ProfileState,
5
+ ProfileClass,
6
+ NotificationEvent,
7
+ CancelSessionReason,
8
+ EnableProfileResult,
9
+ DisableProfileResult,
10
+ DeleteProfileResult,
11
+ BppInstallErrorCode,
12
+ } from './types.js';
13
+
14
+ export type {
15
+ DeviceAdapter,
16
+ ServerAdapter,
17
+ ServerResponse,
18
+ Profile,
19
+ Notification,
20
+ NotificationMetadata,
21
+ NotificationWithResult,
22
+ SendResult,
23
+ ProcessNotificationsOptions,
24
+ ProcessNotificationsResult,
25
+ ProfileInstallationResult,
26
+ ActivationCode,
27
+ DownloadStep,
28
+ DownloadProgress,
29
+ DownloadResult,
30
+ InstallProfileOptions,
31
+ EsimLpaOptions,
32
+ } from './types.js';
33
+
34
+ export {
35
+ EsimError,
36
+ DeviceError,
37
+ Es10Error,
38
+ Es9PlusError,
39
+ TlvError,
40
+ ActivationCodeError,
41
+ } from './errors.js';
42
+
43
+ export { parseActivationCode, isValidActivationCode, formatActivationCode } from './activation-code.js';