samlesa 2.18.2 → 2.18.4
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.
- package/build/src/binding-artifact.js +1 -1
- package/build/src/extractor.js +18 -1
- package/build/src/flow.js +118 -122
- package/build/src/libsaml.js +85 -214
- package/package.json +17 -17
- package/types/src/extractor.d.ts.map +1 -1
- package/types/src/flow.d.ts.map +1 -1
- package/types/src/libsaml.d.ts +13 -21
- package/types/src/libsaml.d.ts.map +1 -1
- package/types/src/utility.d.ts +1 -1
- package/types/src/utility.d.ts.map +1 -1
|
@@ -384,7 +384,7 @@ async function parseLoginResponseResolve(params) {
|
|
|
384
384
|
}
|
|
385
385
|
samlContent = verifiedAssertionNode1;
|
|
386
386
|
// 改进的postFlow函数中关于签名验证的部分
|
|
387
|
-
const verificationResult = libsaml.verifySignature(samlContent, verificationOptions, self);
|
|
387
|
+
const verificationResult = await libsaml.verifySignature(samlContent, verificationOptions, self);
|
|
388
388
|
// 检查验证结果
|
|
389
389
|
if (!verificationResult.status) {
|
|
390
390
|
// 如果验证失败,根据具体情况返回错误
|
package/build/src/extractor.js
CHANGED
|
@@ -173,7 +173,24 @@ export const loginResponseFields = assertion => [
|
|
|
173
173
|
attributePath: ['AttributeValue'],
|
|
174
174
|
attributes: [],
|
|
175
175
|
shortcut: assertion
|
|
176
|
-
}
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
key: 'subjectConfirmation',
|
|
179
|
+
localPath: ['Assertion', 'Subject', 'SubjectConfirmation', 'SubjectConfirmationData'],
|
|
180
|
+
attributes: ['Recipient', 'InResponseTo', 'NotOnOrAfter'],
|
|
181
|
+
shortcut: assertion
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
key: 'oneTimeUse',
|
|
185
|
+
localPath: ['Assertion', 'Conditions', 'OneTimeUse'],
|
|
186
|
+
attributes: [],
|
|
187
|
+
shortcut: assertion
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
key: 'status',
|
|
191
|
+
localPath: ['Response', 'Status', 'StatusCode'],
|
|
192
|
+
attributes: ['Value']
|
|
193
|
+
},
|
|
177
194
|
];
|
|
178
195
|
export const logoutRequestFields = [
|
|
179
196
|
{
|
package/build/src/flow.js
CHANGED
|
@@ -107,7 +107,7 @@ async function redirectFlow(options) {
|
|
|
107
107
|
if (parserType === 'SAMLResponse'
|
|
108
108
|
&& extractedProperties.conditions
|
|
109
109
|
&& !verifyTime(extractedProperties.conditions.notBefore, extractedProperties.conditions.notOnOrAfter, self.entitySetting.clockDrifts)) {
|
|
110
|
-
return Promise.reject('
|
|
110
|
+
return Promise.reject('ERR_CONDITION_UNCONFIRMED');
|
|
111
111
|
}
|
|
112
112
|
if (parserType === 'SAMLResponse') {
|
|
113
113
|
let destination = extractedProperties?.response?.destination;
|
|
@@ -151,107 +151,8 @@ async function postFlow(options) {
|
|
|
151
151
|
// check status based on different scenarios
|
|
152
152
|
await checkStatus(samlContent, parserType);
|
|
153
153
|
/**检查签名顺序 */
|
|
154
|
-
/*
|
|
155
|
-
const [verified, verifiedAssertionNode, isDecryptRequired, noSignature] = libsaml.verifySignature(samlContent, verificationOptions);
|
|
156
|
-
decryptRequired = isDecryptRequired
|
|
157
|
-
if (isDecryptRequired && noSignature) {
|
|
158
|
-
|
|
159
|
-
const result = await libsaml.decryptAssertion(self, samlContent);
|
|
160
|
-
samlContent = result[0];
|
|
161
|
-
extractorFields = getDefaultExtractorFields(parserType, result[1]);
|
|
162
|
-
}
|
|
163
|
-
if (!verified && !noSignature && !isDecryptRequired) {
|
|
164
|
-
|
|
165
|
-
return Promise.reject('ERR_FAIL_TO_VERIFY_ETS_SIGNATURE');
|
|
166
|
-
}
|
|
167
|
-
if (!isDecryptRequired) {
|
|
168
|
-
|
|
169
|
-
extractorFields = getDefaultExtractorFields(parserType, verifiedAssertionNode);
|
|
170
|
-
}
|
|
171
|
-
if (parserType === 'SAMLResponse' && isDecryptRequired && !noSignature) {
|
|
172
|
-
const result = await libsaml.decryptAssertion(self, samlContent);
|
|
173
|
-
samlContent = result[0];
|
|
174
|
-
extractorFields = getDefaultExtractorFields(parserType, result[1]);
|
|
175
|
-
console.log("走这里来了=========")
|
|
176
|
-
console.log(result[1])
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const parseResult = {
|
|
181
|
-
samlContent: samlContent,
|
|
182
|
-
extract: extract(samlContent, extractorFields),
|
|
183
|
-
};
|
|
184
|
-
/!**
|
|
185
|
-
* Validation part: validate the context of response after signature is verified and decrypted (optional)
|
|
186
|
-
*!/
|
|
187
|
-
const targetEntityMetadata = from.entityMeta;
|
|
188
|
-
const issuer = targetEntityMetadata.getEntityID();
|
|
189
|
-
const extractedProperties = parseResult.extract;
|
|
190
|
-
// unmatched issuer
|
|
191
|
-
if (
|
|
192
|
-
(parserType === 'LogoutResponse' || parserType === 'SAMLResponse')
|
|
193
|
-
&& extractedProperties
|
|
194
|
-
&& extractedProperties.issuer !== issuer
|
|
195
|
-
) {
|
|
196
|
-
return Promise.reject('ERR_UNMATCH_ISSUER');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// invalid session time
|
|
200
|
-
// only run the verifyTime when `SessionNotOnOrAfter` exists
|
|
201
|
-
if (
|
|
202
|
-
parserType === 'SAMLResponse'
|
|
203
|
-
&& extractedProperties.sessionIndex.sessionNotOnOrAfter
|
|
204
|
-
&& !verifyTime(
|
|
205
|
-
undefined,
|
|
206
|
-
extractedProperties.sessionIndex.sessionNotOnOrAfter,
|
|
207
|
-
self.entitySetting.clockDrifts
|
|
208
|
-
)
|
|
209
|
-
) {
|
|
210
|
-
return Promise.reject('ERR_EXPIRED_SESSION');
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// invalid time
|
|
214
|
-
// 2.4.1.2 https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
|
215
|
-
if (
|
|
216
|
-
parserType === 'SAMLResponse'
|
|
217
|
-
&& extractedProperties.conditions
|
|
218
|
-
&& !verifyTime(
|
|
219
|
-
extractedProperties.conditions.notBefore,
|
|
220
|
-
extractedProperties.conditions.notOnOrAfter,
|
|
221
|
-
self.entitySetting.clockDrifts
|
|
222
|
-
)
|
|
223
|
-
) {
|
|
224
|
-
return Promise.reject('ERR_SUBJECT_UNCONFIRMED');
|
|
225
|
-
}
|
|
226
|
-
//valid destination
|
|
227
|
-
//There is no validation of the response here. The upper-layer application
|
|
228
|
-
// should verify the result by itself to see if the destination is equal to the SP acs and
|
|
229
|
-
// whether the response.id is used to prevent replay attacks.
|
|
230
|
-
/!*
|
|
231
|
-
let destination = extractedProperties?.response?.destination
|
|
232
|
-
let isExit = self.entitySetting?.assertionConsumerService?.filter((item) => {
|
|
233
|
-
return item?.Location === destination
|
|
234
|
-
})
|
|
235
|
-
if (isExit?.length === 0) {
|
|
236
|
-
return Promise.reject('ERR_Destination_URL');
|
|
237
|
-
}
|
|
238
|
-
if (parserType === 'SAMLResponse') {
|
|
239
|
-
let destination = extractedProperties?.response?.destination
|
|
240
|
-
let isExit = self.entitySetting?.assertionConsumerService?.filter((item: { Location: any; }) => {
|
|
241
|
-
return item?.Location === destination
|
|
242
|
-
})
|
|
243
|
-
if (isExit?.length === 0) {
|
|
244
|
-
return Promise.reject('ERR_Destination_URL');
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
*!/
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
return Promise.resolve(parseResult);*/
|
|
251
154
|
// 改进的postFlow函数中关于签名验证的部分
|
|
252
|
-
const verificationResult = libsaml.verifySignature(samlContent, verificationOptions, self);
|
|
253
|
-
/* console.log(verificationResult)
|
|
254
|
-
console.log("解析对象")*/
|
|
155
|
+
const verificationResult = await libsaml.verifySignature(samlContent, verificationOptions, self);
|
|
255
156
|
let resultObject = {
|
|
256
157
|
isMessageSigned: true, //是否有外层的消息签名(Response或者Request 等最外层的签名)
|
|
257
158
|
MessageSignatureStatus: true, //外层的签名是否经过验证
|
|
@@ -261,7 +162,8 @@ async function postFlow(options) {
|
|
|
261
162
|
decrypted: true, //断言加密后断言是否解密成功,
|
|
262
163
|
status: true, //是否全部通过验证,
|
|
263
164
|
samlContent: 'xxx', //xxx是通过验证后 解密后的整个响应,
|
|
264
|
-
assertionContent: 'xxx', //xxx是通过验证后 解密后的整个响应中的assertion
|
|
165
|
+
assertionContent: 'xxx', //xxx是通过验证后 解密后的整个响应中的assertion 断言部分字符串,
|
|
166
|
+
signMethod: "", //xxx是通过验证后 解密后的整个响应中的assertion 断言部分字符串,
|
|
265
167
|
};
|
|
266
168
|
// 检查验证结果
|
|
267
169
|
if (!verificationResult.status) {
|
|
@@ -323,31 +225,126 @@ async function postFlow(options) {
|
|
|
323
225
|
if (parserType === 'SAMLResponse'
|
|
324
226
|
&& extractedProperties.conditions
|
|
325
227
|
&& !verifyTime(extractedProperties.conditions.notBefore, extractedProperties.conditions.notOnOrAfter, self.entitySetting.clockDrifts)) {
|
|
228
|
+
return Promise.reject('ERR_CONDITION_SESSION');
|
|
229
|
+
}
|
|
230
|
+
// invalid subjectConfirmation time
|
|
231
|
+
// invalid time
|
|
232
|
+
// 2.4.1.2 https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
|
233
|
+
if (parserType === 'SAMLResponse'
|
|
234
|
+
&& extractedProperties.subjectConfirmation
|
|
235
|
+
&& !verifyTime(undefined, extractedProperties.subjectConfirmation.notOnOrAfter, self.entitySetting.clockDrifts)) {
|
|
326
236
|
return Promise.reject('ERR_SUBJECT_UNCONFIRMED');
|
|
327
237
|
}
|
|
328
238
|
//valid destination
|
|
329
239
|
//There is no validation of the response here. The upper-layer application
|
|
330
240
|
// should verify the result by itself to see if the destination is equal to the SP acs and
|
|
331
241
|
// whether the response.id is used to prevent replay attacks.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
let
|
|
335
|
-
|
|
336
|
-
})
|
|
337
|
-
if (isExit?.length === 0) {
|
|
338
|
-
return Promise.reject('ERR_Destination_URL');
|
|
339
|
-
}
|
|
340
|
-
if (parserType === 'SAMLResponse') {
|
|
341
|
-
let destination = extractedProperties?.response?.destination
|
|
342
|
-
let isExit = self.entitySetting?.assertionConsumerService?.filter((item: { Location: any; }) => {
|
|
242
|
+
console.log(extractedProperties);
|
|
243
|
+
console.log("牛逼属性");
|
|
244
|
+
/* let destination = extractedProperties?.response?.destination
|
|
245
|
+
let isExit = self.entitySetting?.assertionConsumerService?.filter((item) => {
|
|
343
246
|
return item?.Location === destination
|
|
344
247
|
})
|
|
345
248
|
if (isExit?.length === 0) {
|
|
346
249
|
return Promise.reject('ERR_Destination_URL');
|
|
347
250
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
251
|
+
if (parserType === 'SAMLResponse') {
|
|
252
|
+
let destination = extractedProperties?.response?.destination
|
|
253
|
+
let isExit = self.entitySetting?.assertionConsumerService?.filter((item: { Location: any; }) => {
|
|
254
|
+
return item?.Location === destination
|
|
255
|
+
})
|
|
256
|
+
if (isExit?.length === 0) {
|
|
257
|
+
return Promise.reject('ERR_Destination_URL');
|
|
258
|
+
}
|
|
259
|
+
}*/
|
|
260
|
+
// ============================
|
|
261
|
+
// VALIDATE Destination & Recipient
|
|
262
|
+
// ============================
|
|
263
|
+
const { type } = verificationResult;
|
|
264
|
+
const { response, subjectConfirmation } = extractedProperties || {};
|
|
265
|
+
// 获取 SP 配置的所有合法 ACS URLs(用于比对)
|
|
266
|
+
const validACSUrls = (self.entitySetting?.assertionConsumerService || [])
|
|
267
|
+
.map((item) => item.Location)
|
|
268
|
+
.filter(Boolean);
|
|
269
|
+
/**
|
|
270
|
+
* Helper: Check if a given URL is in the list of valid ACS endpoints
|
|
271
|
+
*/
|
|
272
|
+
function isValidACSEndpoint(url) {
|
|
273
|
+
return url != null && validACSUrls.includes(url);
|
|
274
|
+
}
|
|
275
|
+
// 根据消息类型执行不同的验证
|
|
276
|
+
switch (type) {
|
|
277
|
+
case 'Response': // SAML Response (Login)
|
|
278
|
+
{
|
|
279
|
+
// 1. 验证协议层 Destination(必须匹配 ACS)
|
|
280
|
+
const destination = response?.destination;
|
|
281
|
+
if (!isValidACSEndpoint(destination)) {
|
|
282
|
+
return Promise.reject('ERR_INVALID_DESTINATION');
|
|
283
|
+
}
|
|
284
|
+
// 2. 验证断言层 Recipient(必须匹配 ACS,且通常应等于 Destination)
|
|
285
|
+
const recipient = subjectConfirmation?.recipient;
|
|
286
|
+
if (!isValidACSEndpoint(recipient)) {
|
|
287
|
+
return Promise.reject('ERR_INVALID_RECIPIENT');
|
|
288
|
+
}
|
|
289
|
+
// 可选:强制 Destination === Recipient(推荐)
|
|
290
|
+
if (destination !== recipient) {
|
|
291
|
+
// 注意:某些 IdP 可能不严格一致,但安全起见建议开启
|
|
292
|
+
return Promise.reject('ERR_DESTINATION_RECIPIENT_MISMATCH');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
break;
|
|
296
|
+
case 'LogoutRequest': // IdP 发起的单点登出
|
|
297
|
+
{
|
|
298
|
+
// LogoutRequest 是 IdP → SP,SP 是接收方
|
|
299
|
+
// 必须验证 Destination 是否为 SP 的 SLO endpoint(Single Logout Service)
|
|
300
|
+
const destination = response?.destination; // 注意:LogoutRequest 的 root 元素是 <samlp:LogoutRequest>
|
|
301
|
+
const validSLOUrls = (self.entitySetting?.singleLogoutService || [])
|
|
302
|
+
.map((item) => item.Location)
|
|
303
|
+
.filter(Boolean);
|
|
304
|
+
if (destination && !validSLOUrls.includes(destination)) {
|
|
305
|
+
return Promise.reject('ERR_INVALID_LOGOUT_DESTINATION');
|
|
306
|
+
}
|
|
307
|
+
// LogoutRequest 通常**不包含 Assertion**,所以无 Recipient
|
|
308
|
+
// 如果有嵌套断言(罕见),可额外处理,但一般不需要
|
|
309
|
+
}
|
|
310
|
+
break;
|
|
311
|
+
case 'LogoutResponse': // SP → IdP 的登出响应
|
|
312
|
+
{
|
|
313
|
+
// LogoutResponse 是 SP → IdP,IdP 是接收方
|
|
314
|
+
// 此时 SP 是发送方,**不应验证 Destination 是否属于自身**
|
|
315
|
+
// 而应由 IdP 验证。因此 SP 端通常**跳过 Destination 验证**
|
|
316
|
+
// 但如果你作为 SP 也要校验(比如防止发错),可对比 IdP 的 SLO URL
|
|
317
|
+
// —— 但你的 entityMeta 是 SP 自身,没有 IdP 的 SLO,所以一般不验
|
|
318
|
+
// ✅ 所以:LogoutResponse 在 SP 端通常**无需验证 Destination/Recipient**
|
|
319
|
+
}
|
|
320
|
+
break;
|
|
321
|
+
case 'AuthnRequest': // SP → IdP 的认证请求
|
|
322
|
+
{
|
|
323
|
+
// AuthnRequest 是 SP 发出的,不是接收的
|
|
324
|
+
// 此验证逻辑运行在 SP 接收响应时,**不会收到 AuthnRequest**
|
|
325
|
+
// 所以这个 case 实际不会触发,保留仅为完整性
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
case 'Unknown':
|
|
329
|
+
default:
|
|
330
|
+
// 未知类型,保守拒绝
|
|
331
|
+
return Promise.reject('ERR_UNKNOWN_SAML_MESSAGE_TYPE');
|
|
332
|
+
}
|
|
333
|
+
return Promise.resolve({
|
|
334
|
+
...parseResult,
|
|
335
|
+
verificationResult: {
|
|
336
|
+
isMessageSigned: verificationResult?.isMessageSigned,
|
|
337
|
+
MessageSignatureStatus: verificationResult?.MessageSignatureStatus,
|
|
338
|
+
isAssertionSigned: verificationResult?.isAssertionSigned,
|
|
339
|
+
AssertionSignatureStatus: verificationResult?.AssertionSignatureStatus,
|
|
340
|
+
encrypted: verificationResult?.encrypted,
|
|
341
|
+
decrypted: verificationResult?.decrypted,
|
|
342
|
+
type: verificationResult?.type, // 添加类型字段
|
|
343
|
+
status: verificationResult?.status,
|
|
344
|
+
hasUnsafeSignatureAlgorithm: verificationResult?.hasUnsafeSignatureAlgorithm,
|
|
345
|
+
unsafeSignatureAlgorithm: verificationResult?.unsafeSignatureAlgorithm
|
|
346
|
+
},
|
|
347
|
+
});
|
|
351
348
|
}
|
|
352
349
|
// proceed the post Artifact flow
|
|
353
350
|
async function postArtifactFlow(options) {
|
|
@@ -372,9 +369,7 @@ async function postArtifactFlow(options) {
|
|
|
372
369
|
await checkStatus(samlContent, parserType);
|
|
373
370
|
/**检查签名顺序 */
|
|
374
371
|
// 改进的postFlow函数中关于签名验证的部分
|
|
375
|
-
const verificationResult = libsaml.verifySignature(samlContent, verificationOptions, self);
|
|
376
|
-
console.log(verificationResult);
|
|
377
|
-
console.log("最终结果====");
|
|
372
|
+
const verificationResult = await libsaml.verifySignature(samlContent, verificationOptions, self);
|
|
378
373
|
// 检查验证结果
|
|
379
374
|
if (!verificationResult.status) {
|
|
380
375
|
// 如果验证失败,根据具体情况返回错误
|
|
@@ -428,7 +423,7 @@ async function postArtifactFlow(options) {
|
|
|
428
423
|
if (parserType === 'SAMLResponse'
|
|
429
424
|
&& extractedProperties.conditions
|
|
430
425
|
&& !verifyTime(extractedProperties.conditions.notBefore, extractedProperties.conditions.notOnOrAfter, self.entitySetting.clockDrifts)) {
|
|
431
|
-
return Promise.reject('
|
|
426
|
+
return Promise.reject('ERR_CONDITION_UNCONFIRMED');
|
|
432
427
|
}
|
|
433
428
|
//valid destination
|
|
434
429
|
//There is no validation of the response here. The upper-layer application
|
|
@@ -533,7 +528,7 @@ async function postSimpleSignFlow(options) {
|
|
|
533
528
|
if (parserType === 'SAMLResponse'
|
|
534
529
|
&& extractedProperties.conditions
|
|
535
530
|
&& !verifyTime(extractedProperties.conditions.notBefore, extractedProperties.conditions.notOnOrAfter, self.entitySetting.clockDrifts)) {
|
|
536
|
-
return Promise.reject('
|
|
531
|
+
return Promise.reject('ERR_CONDITION_UNCONFIRMED');
|
|
537
532
|
}
|
|
538
533
|
if (parserType === 'SAMLResponse') {
|
|
539
534
|
let destination = extractedProperties?.response?.destination;
|
|
@@ -568,7 +563,8 @@ export function checkStatus(content, parserType, soap) {
|
|
|
568
563
|
throw new Error('ERR_UNDEFINED_STATUS');
|
|
569
564
|
}
|
|
570
565
|
// returns a detailed error for two-tier error code
|
|
571
|
-
throw new Error(
|
|
566
|
+
throw new Error('ERR_UNDEFINED_STATUS');
|
|
567
|
+
/* throw new Error(`ERR_FAILED_STATUS with top tier code: ${top}, second tier code: ${second}`);*/
|
|
572
568
|
}
|
|
573
569
|
export function flow(options) {
|
|
574
570
|
const binding = options.binding;
|
package/build/src/libsaml.js
CHANGED
|
@@ -7,7 +7,7 @@ import { X509Certificate } from 'node:crypto';
|
|
|
7
7
|
import xml from 'xml';
|
|
8
8
|
import utility, { flattenDeep, inflateString, isString } from './utility.js';
|
|
9
9
|
import { algorithms, namespace, wording } from './urn.js';
|
|
10
|
-
import { select } from 'xpath';
|
|
10
|
+
import xpath, { select } from 'xpath';
|
|
11
11
|
import nrsa from 'node-rsa';
|
|
12
12
|
import { SignedXml } from 'xml-crypto';
|
|
13
13
|
import * as xmlenc from 'xml-encryption';
|
|
@@ -48,6 +48,25 @@ const libSaml = () => {
|
|
|
48
48
|
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256': 'RSA-SHA256',
|
|
49
49
|
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512': 'RSA-SHA512',
|
|
50
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* 检测是否使用了不安全的SHA1系列签名算法
|
|
53
|
+
* @param signatureAlgorithm 签名算法URI
|
|
54
|
+
* @returns {Object} 包含是否使用不安全算法和具体算法名称的对象
|
|
55
|
+
*/
|
|
56
|
+
function checkUnsafeSignatureAlgorithm(signatureAlgorithm) {
|
|
57
|
+
const unsafeAlgorithms = [
|
|
58
|
+
'http://www.w3.org/2000/09/xmldsig#rsa-sha1',
|
|
59
|
+
'http://www.w3.org/2000/09/xmldsig#dsa-sha1',
|
|
60
|
+
'http://www.w3.org/2000/09/xmldsig#hmac-sha1',
|
|
61
|
+
'http://www.w3.org/2000/09/xmldsig#sha1'
|
|
62
|
+
];
|
|
63
|
+
const isUnsafe = unsafeAlgorithms.some(alg => signatureAlgorithm.toLowerCase().includes('sha1') ||
|
|
64
|
+
signatureAlgorithm === 'http://www.w3.org/2000/09/xmldsig#rsa-sha1');
|
|
65
|
+
return {
|
|
66
|
+
hasUnsafeSignatureAlgorithm: isUnsafe,
|
|
67
|
+
unsafeSignatureAlgorithm: isUnsafe ? signatureAlgorithm : null
|
|
68
|
+
};
|
|
69
|
+
}
|
|
51
70
|
/**
|
|
52
71
|
* @desc Default login request template
|
|
53
72
|
* @type {LoginRequestTemplate}
|
|
@@ -229,6 +248,7 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
229
248
|
defaultLogoutResponseTemplate,
|
|
230
249
|
defaultAttributeValueTemplate,
|
|
231
250
|
validateAndInflateSamlResponse,
|
|
251
|
+
checkUnsafeSignatureAlgorithm,
|
|
232
252
|
/**
|
|
233
253
|
* @desc Replace the tag (e.g. {tag}) inside the raw XML
|
|
234
254
|
* @param {string} rawXML raw XML string used to do keyword replacement
|
|
@@ -294,7 +314,7 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
294
314
|
* @desc Construct the XML signature for POST binding
|
|
295
315
|
* @param {string} rawSamlMessage request/response xml string
|
|
296
316
|
* @param {string} referenceTagXPath reference uri
|
|
297
|
-
* @param {string} privateKey declares the private key
|
|
317
|
+
* @param {string} privateKey declares the private key-
|
|
298
318
|
* @param {string} passphrase passphrase of the private key [optional]
|
|
299
319
|
* @param {string|buffer} signingCert signing certificate
|
|
300
320
|
* @param {string} signatureAlgorithm signature algorithm
|
|
@@ -368,201 +388,6 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
368
388
|
};
|
|
369
389
|
}
|
|
370
390
|
},
|
|
371
|
-
/**
|
|
372
|
-
* @desc Verify the XML signature
|
|
373
|
-
* @param {string} xml xml
|
|
374
|
-
* @param {SignatureVerifierOptions} opts cert declares the X509 certificate
|
|
375
|
-
* @return {[boolean, string | null]} - A tuple where:
|
|
376
|
-
* - The first element is `true` if the signature is valid, `false` otherwise.
|
|
377
|
-
* - The second element is the cryptographically authenticated assertion node as a string, or `null` if not found.
|
|
378
|
-
*/
|
|
379
|
-
// tslint:disable-next-line:no-shadowed-variable
|
|
380
|
-
verifySignature1(xml, opts) {
|
|
381
|
-
const { dom } = getContext();
|
|
382
|
-
const doc = dom.parseFromString(xml, 'application/xml');
|
|
383
|
-
const docParser = new DOMParser();
|
|
384
|
-
// In order to avoid the wrapping attack, we have changed to use absolute xpath instead of naively fetching the signature element
|
|
385
|
-
const LogoutResponseSignatureXpath = "/*[local-name()='LogoutResponse']/*[local-name()='Signature']";
|
|
386
|
-
const logoutRequestSignatureXpath = "/*[local-name()='LogoutRequest']/*[local-name()='Signature']";
|
|
387
|
-
// message signature (logout response / saml response)
|
|
388
|
-
const messageSignatureXpath = "/*[contains(local-name(), 'Response') or contains(local-name(), 'Request')]/*[local-name(.)='Signature']";
|
|
389
|
-
// assertion signature (logout response / saml response)
|
|
390
|
-
const assertionSignatureXpath = "/*[contains(local-name(), 'Response') or contains(local-name(), 'Request')]/*[local-name(.)='Assertion']/*[local-name(.)='Signature']";
|
|
391
|
-
// check if there is a potential malicious wrapping signature
|
|
392
|
-
const wrappingElementsXPath = "/*[contains(local-name(), 'Response')]/*[local-name(.)='Assertion']/*[local-name(.)='Subject']/*[local-name(.)='SubjectConfirmation']/*[local-name(.)='SubjectConfirmationData']//*[local-name(.)='Assertion' or local-name(.)='Signature']";
|
|
393
|
-
// const wrappingElementsXPath = "/*[contains(local-name(), 'Response')]/*[local-name(.)='Assertion']/*[local-name(.)='Subject']/*[local-name(.)='SubjectConfirmation']/*[local-name(.)='SubjectConfirmationData']//*[local-name(.)='Assertion' or local-name(.)='Signature']";
|
|
394
|
-
// @ts-expect-error misssing Node properties are not needed
|
|
395
|
-
const encryptedAssertions = select("/*[contains(local-name(), 'Response')]/*[local-name(.)='EncryptedAssertion']", doc);
|
|
396
|
-
const encAssertionNode = encryptedAssertions[0];
|
|
397
|
-
// select the signature node
|
|
398
|
-
let selection = [];
|
|
399
|
-
// @ts-expect-error misssing Node properties are not needed
|
|
400
|
-
const messageSignatureNode = select(messageSignatureXpath, doc);
|
|
401
|
-
// @ts-expect-error misssing Node properties are not needed
|
|
402
|
-
const assertionSignatureNode = select(assertionSignatureXpath, doc);
|
|
403
|
-
// @ts-expect-error misssing Node properties are not needed
|
|
404
|
-
const wrappingElementNode = select(wrappingElementsXPath, doc);
|
|
405
|
-
// @ts-expect-error misssing Node properties are not needed
|
|
406
|
-
const LogoutResponseSignatureElementNode = select(LogoutResponseSignatureXpath, doc);
|
|
407
|
-
// try to catch potential wrapping attack
|
|
408
|
-
if (wrappingElementNode.length !== 0) {
|
|
409
|
-
throw new Error('ERR_POTENTIAL_WRAPPING_ATTACK');
|
|
410
|
-
}
|
|
411
|
-
// 优先检测 LogoutRequest 签名
|
|
412
|
-
// @ts-expect-error missing Node properties
|
|
413
|
-
const logoutRequestSignature = select(logoutRequestSignatureXpath, doc);
|
|
414
|
-
if (logoutRequestSignature.length > 0) {
|
|
415
|
-
selection = selection.concat(logoutRequestSignature);
|
|
416
|
-
}
|
|
417
|
-
selection = selection.concat(messageSignatureNode);
|
|
418
|
-
selection = selection.concat(assertionSignatureNode);
|
|
419
|
-
selection = selection.concat(LogoutResponseSignatureElementNode);
|
|
420
|
-
// guarantee to have a signature in saml response
|
|
421
|
-
if (selection.length === 0) {
|
|
422
|
-
/** 判断有没有加密如果没有加密返回 [false, null]*/
|
|
423
|
-
if (encryptedAssertions.length > 0) {
|
|
424
|
-
console.log("走加密了====");
|
|
425
|
-
if (!Array.isArray(encryptedAssertions) || encryptedAssertions.length === 0) {
|
|
426
|
-
return [false, null, false, true]; // we return false now
|
|
427
|
-
}
|
|
428
|
-
if (encryptedAssertions.length > 1) {
|
|
429
|
-
throw new Error('ERR_MULTIPLE_ASSERTION');
|
|
430
|
-
}
|
|
431
|
-
return [false, null, true, true]; // return encryptedAssert
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
if (selection.length !== 0) {
|
|
435
|
-
console.log("走加密了1====");
|
|
436
|
-
/** 判断有没有加密如果没有加密返回 [false, null]*/
|
|
437
|
-
if (logoutRequestSignature.length === 0 && LogoutResponseSignatureElementNode.length === 0 && encryptedAssertions.length > 0) {
|
|
438
|
-
if (!Array.isArray(encryptedAssertions) || encryptedAssertions.length === 0) {
|
|
439
|
-
return [false, null, true, false]; // we return false now
|
|
440
|
-
}
|
|
441
|
-
if (encryptedAssertions.length > 1) {
|
|
442
|
-
throw new Error('ERR_MULTIPLE_ASSERTION');
|
|
443
|
-
}
|
|
444
|
-
return [false, null, true, false]; // return encryptedAssert
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
// need to refactor later on
|
|
448
|
-
for (const signatureNode of selection) {
|
|
449
|
-
const sig = new SignedXml();
|
|
450
|
-
let verified = false;
|
|
451
|
-
sig.signatureAlgorithm = opts.signatureAlgorithm;
|
|
452
|
-
if (!opts.keyFile && !opts.metadata) {
|
|
453
|
-
throw new Error('ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS');
|
|
454
|
-
}
|
|
455
|
-
console.log("开始1");
|
|
456
|
-
if (opts.keyFile) {
|
|
457
|
-
console.log("开始11");
|
|
458
|
-
let publicCertResult = this.validateCertificate(fs.readFileSync(opts.keyFile));
|
|
459
|
-
console.log(publicCertResult);
|
|
460
|
-
console.log("结果");
|
|
461
|
-
sig.publicCert = fs.readFileSync(opts.keyFile);
|
|
462
|
-
}
|
|
463
|
-
if (opts.metadata) {
|
|
464
|
-
console.log("开始111");
|
|
465
|
-
const certificateNode = select(".//*[local-name(.)='X509Certificate']", signatureNode);
|
|
466
|
-
// certificate in metadata
|
|
467
|
-
let metadataCert = opts.metadata.getX509Certificate(certUse.signing);
|
|
468
|
-
// flattens the nested array of Certificates from each KeyDescriptor
|
|
469
|
-
if (Array.isArray(metadataCert)) {
|
|
470
|
-
metadataCert = flattenDeep(metadataCert);
|
|
471
|
-
}
|
|
472
|
-
else if (typeof metadataCert === 'string') {
|
|
473
|
-
metadataCert = [metadataCert];
|
|
474
|
-
}
|
|
475
|
-
// normalise the certificate string
|
|
476
|
-
metadataCert = metadataCert.map(utility.normalizeCerString);
|
|
477
|
-
// no certificate in node response nor metadata
|
|
478
|
-
if (certificateNode.length === 0 && metadataCert.length === 0) {
|
|
479
|
-
throw new Error('NO_SELECTED_CERTIFICATE');
|
|
480
|
-
}
|
|
481
|
-
// certificate node in response
|
|
482
|
-
if (certificateNode.length !== 0) {
|
|
483
|
-
const x509CertificateData = certificateNode[0].firstChild.data;
|
|
484
|
-
const x509Certificate = utility.normalizeCerString(x509CertificateData);
|
|
485
|
-
if (metadataCert.length >= 1 &&
|
|
486
|
-
!metadataCert.find(cert => cert.trim() === x509Certificate.trim())) {
|
|
487
|
-
// keep this restriction for rolling certificate usage
|
|
488
|
-
// to make sure the response certificate is one of those specified in metadata
|
|
489
|
-
throw new Error('ERROR_UNMATCH_CERTIFICATE_DECLARATION_IN_METADATA');
|
|
490
|
-
}
|
|
491
|
-
let publicCertResult = this.validateCertificate(x509Certificate);
|
|
492
|
-
console.log(publicCertResult);
|
|
493
|
-
console.log("结果");
|
|
494
|
-
sig.publicCert = this.getKeyInfo(x509Certificate).getKey();
|
|
495
|
-
}
|
|
496
|
-
else {
|
|
497
|
-
console.log("开始11111");
|
|
498
|
-
// Select first one from metadata
|
|
499
|
-
let publicCertResult = this.validateCertificate(metadataCert[0]);
|
|
500
|
-
console.log(publicCertResult);
|
|
501
|
-
console.log("结果");
|
|
502
|
-
sig.publicCert = this.getKeyInfo(metadataCert[0]).getKey();
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
sig.loadSignature(signatureNode);
|
|
506
|
-
verified = sig.checkSignature(doc.toString());
|
|
507
|
-
// immediately throw error when any one of the signature is failed to get verified
|
|
508
|
-
if (!verified) {
|
|
509
|
-
throw new Error('ERR_FAILED_TO_VERIFY_SIGNATURE');
|
|
510
|
-
}
|
|
511
|
-
// attempt is made to get the signed Reference as a string();
|
|
512
|
-
// note, we don't have access to the actual signedReferences API unfortunately
|
|
513
|
-
// mainly a sanity check here for SAML. (Although ours would still be secure, if multiple references are used)
|
|
514
|
-
if (!(sig.getSignedReferences().length >= 1)) {
|
|
515
|
-
throw new Error('NO_SIGNATURE_REFERENCES');
|
|
516
|
-
}
|
|
517
|
-
const signedVerifiedXML = sig.getSignedReferences()[0];
|
|
518
|
-
const rootNode = docParser.parseFromString(signedVerifiedXML, 'application/xml').documentElement;
|
|
519
|
-
// process the verified signature:
|
|
520
|
-
// case 1, rootSignedDoc is a response:
|
|
521
|
-
if (rootNode?.localName === 'Response') {
|
|
522
|
-
// try getting the Xml from the first assertion
|
|
523
|
-
const EncryptedAssertions = select("./*[local-name()='EncryptedAssertion']",
|
|
524
|
-
// @ts-expect-error misssing Node properties are not needed
|
|
525
|
-
rootNode);
|
|
526
|
-
const assertions = select("./*[local-name()='Assertion']",
|
|
527
|
-
// @ts-expect-error misssing Node properties are not needed
|
|
528
|
-
rootNode);
|
|
529
|
-
/**第三个参数代表是否加密*/
|
|
530
|
-
// now we can process the assertion as an assertion
|
|
531
|
-
if (EncryptedAssertions.length === 1) {
|
|
532
|
-
/** 已加密*/
|
|
533
|
-
return [true, EncryptedAssertions[0].toString(), true, false];
|
|
534
|
-
}
|
|
535
|
-
if (assertions.length === 1) {
|
|
536
|
-
return [true, assertions[0].toString(), false, false];
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
else if (rootNode?.localName === 'Assertion') {
|
|
540
|
-
return [true, rootNode.toString(), false, false];
|
|
541
|
-
}
|
|
542
|
-
else if (rootNode?.localName === 'EncryptedAssertion') {
|
|
543
|
-
return [true, rootNode.toString(), true, false];
|
|
544
|
-
}
|
|
545
|
-
else if (rootNode?.localName === 'LogoutRequest') {
|
|
546
|
-
return [true, rootNode.toString(), false, false];
|
|
547
|
-
}
|
|
548
|
-
else if (rootNode?.localName === 'LogoutResponse') {
|
|
549
|
-
return [true, rootNode.toString(), false, false];
|
|
550
|
-
}
|
|
551
|
-
else {
|
|
552
|
-
return [true, null, false, false]; // signature is valid. But there is no assertion node here. It could be metadata node, hence return null
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
// something has gone seriously wrong if we are still here
|
|
556
|
-
return [false, null, false, true]; // return encryptedAssert
|
|
557
|
-
/* throw new Error('ERR_ZERO_SIGNATURE');*/
|
|
558
|
-
},
|
|
559
|
-
/**
|
|
560
|
-
* 改进的SAML签名验证函数,支持多种签名和加密组合场景
|
|
561
|
-
* @param xml SAML XML内容
|
|
562
|
-
* @param opts 验证选项
|
|
563
|
-
* @param self
|
|
564
|
-
* @returns 验证结果对象
|
|
565
|
-
*/
|
|
566
391
|
/**
|
|
567
392
|
* 改进的SAML签名验证函数,支持多种签名和加密组合场景
|
|
568
393
|
* @param xml SAML XML内容
|
|
@@ -570,7 +395,7 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
570
395
|
* @param self
|
|
571
396
|
* @returns 验证结果对象
|
|
572
397
|
*/
|
|
573
|
-
verifySignature(xml, opts, self) {
|
|
398
|
+
async verifySignature(xml, opts, self) {
|
|
574
399
|
const { dom } = getContext();
|
|
575
400
|
const doc = dom.parseFromString(xml, 'application/xml');
|
|
576
401
|
const docParser = new DOMParser();
|
|
@@ -638,6 +463,8 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
638
463
|
type = 'Unknown';
|
|
639
464
|
}
|
|
640
465
|
}
|
|
466
|
+
let hasUnsafeSignatureAlgorithm = false;
|
|
467
|
+
let unsafeSignatureAlgorithm = '';
|
|
641
468
|
// 特殊情况:带未签名断言的未签名SAML响应,应该拒绝
|
|
642
469
|
if (!isMessageSigned && !isAssertionSigned && !encrypted) {
|
|
643
470
|
return {
|
|
@@ -650,7 +477,9 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
650
477
|
type, // 添加类型字段
|
|
651
478
|
status: false, // 明确拒绝未签名未加密的响应
|
|
652
479
|
samlContent,
|
|
653
|
-
assertionContent
|
|
480
|
+
assertionContent,
|
|
481
|
+
hasUnsafeSignatureAlgorithm,
|
|
482
|
+
unsafeSignatureAlgorithm
|
|
654
483
|
};
|
|
655
484
|
}
|
|
656
485
|
// 处理最外层有签名且断言加密的情况(关键逻辑补充)
|
|
@@ -660,6 +489,12 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
660
489
|
const result = this.decryptAssertionSync(self, xml, opts);
|
|
661
490
|
// 更新文档为解密后的版本
|
|
662
491
|
samlContent = result[0];
|
|
492
|
+
let res = await this.isValidXml(samlContent).catch((error) => {
|
|
493
|
+
return Promise.reject('ERR_EXCEPTION_VALIDATE_XML');
|
|
494
|
+
});
|
|
495
|
+
if (res !== true) {
|
|
496
|
+
return Promise.reject('ERR_EXCEPTION_VALIDATE_XML');
|
|
497
|
+
}
|
|
663
498
|
assertionContent = result[1];
|
|
664
499
|
// 更新验证状态
|
|
665
500
|
decrypted = true;
|
|
@@ -669,6 +504,11 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
669
504
|
const decryptedDoc = dom.parseFromString(samlContent, 'application/xml');
|
|
670
505
|
// 2. 验证最外层消息签名(使用解密后的文档)
|
|
671
506
|
const signatureNode = messageSignatureNode[0];
|
|
507
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
508
|
+
const signatureAlgorithm = xpath.select1(".//*[local-name(.)='SignatureMethod']/@Algorithm", signatureNode);
|
|
509
|
+
let checkResult = checkUnsafeSignatureAlgorithm(signatureAlgorithm.value || '');
|
|
510
|
+
hasUnsafeSignatureAlgorithm = checkResult.hasUnsafeSignatureAlgorithm;
|
|
511
|
+
unsafeSignatureAlgorithm = checkResult.unsafeSignatureAlgorithm ?? "";
|
|
672
512
|
const sig = new SignedXml();
|
|
673
513
|
if (!opts.keyFile && !opts.metadata) {
|
|
674
514
|
throw new Error('ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS');
|
|
@@ -707,8 +547,6 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
707
547
|
sig.loadSignature(signatureNode);
|
|
708
548
|
// 使用解密后的文档验证最外层签名.默认采用的都是采用的先签名后加密的顺序,对应sp应该先解密 然后验证签名。 如果解密后验证外层签名失败有可能是先加密后签名,此时sp应该直接验证没解密的外层签名
|
|
709
549
|
MessageSignatureStatus = sig.checkSignature(decryptedDoc.toString());
|
|
710
|
-
console.log(MessageSignatureStatus);
|
|
711
|
-
console.log("验证MessageSignatureStatus==========================");
|
|
712
550
|
if (!MessageSignatureStatus) {
|
|
713
551
|
/** 签名验证失败 再直接验证外层*/
|
|
714
552
|
let MessageSignatureStatus2 = sig.checkSignature(xml);
|
|
@@ -734,6 +572,11 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
734
572
|
// 处理最外层有签名但断言未加密的情况
|
|
735
573
|
else if (isMessageSigned && !encrypted) {
|
|
736
574
|
const signatureNode = messageSignatureNode[0];
|
|
575
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
576
|
+
const signatureAlgorithm = xpath.select1(".//*[local-name(.)='SignatureMethod']/@Algorithm", signatureNode);
|
|
577
|
+
let checkResult = checkUnsafeSignatureAlgorithm(signatureAlgorithm.value || '');
|
|
578
|
+
hasUnsafeSignatureAlgorithm = checkResult.hasUnsafeSignatureAlgorithm;
|
|
579
|
+
unsafeSignatureAlgorithm = checkResult.unsafeSignatureAlgorithm ?? "";
|
|
737
580
|
const sig = new SignedXml();
|
|
738
581
|
if (!opts.keyFile && !opts.metadata) {
|
|
739
582
|
throw new Error('ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS');
|
|
@@ -767,7 +610,7 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
767
610
|
sig.publicCert = this.getKeyInfo(metadataCert[0]).getKey();
|
|
768
611
|
}
|
|
769
612
|
}
|
|
770
|
-
sig.signatureAlgorithm =
|
|
613
|
+
sig.signatureAlgorithm = signatureAlgorithm.value;
|
|
771
614
|
// @ts-expect-error misssing Node properties are not needed
|
|
772
615
|
sig.loadSignature(signatureNode);
|
|
773
616
|
MessageSignatureStatus = sig.checkSignature(doc.toString());
|
|
@@ -778,6 +621,11 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
778
621
|
// 验证断言级签名(如果存在且未加密)
|
|
779
622
|
if (isAssertionSigned && !encrypted) {
|
|
780
623
|
const signatureNode = assertionSignatureNode[0];
|
|
624
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
625
|
+
const signatureAlgorithm = xpath.select1(".//*[local-name(.)='SignatureMethod']/@Algorithm", signatureNode);
|
|
626
|
+
let checkResult = checkUnsafeSignatureAlgorithm(signatureAlgorithm.value || '');
|
|
627
|
+
hasUnsafeSignatureAlgorithm = checkResult.hasUnsafeSignatureAlgorithm;
|
|
628
|
+
unsafeSignatureAlgorithm = checkResult.unsafeSignatureAlgorithm ?? "";
|
|
781
629
|
const sig = new SignedXml();
|
|
782
630
|
if (!opts.keyFile && !opts.metadata) {
|
|
783
631
|
throw new Error('ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS');
|
|
@@ -811,6 +659,7 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
811
659
|
sig.publicCert = this.getKeyInfo(metadataCert[0]).getKey();
|
|
812
660
|
}
|
|
813
661
|
}
|
|
662
|
+
// 检测不安全的签名算法
|
|
814
663
|
sig.signatureAlgorithm = opts.signatureAlgorithm;
|
|
815
664
|
// @ts-expect-error misssing Node properties are not needed
|
|
816
665
|
sig.loadSignature(signatureNode);
|
|
@@ -840,6 +689,12 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
840
689
|
// 解密断言
|
|
841
690
|
try {
|
|
842
691
|
const result = this.decryptAssertionSync(self, xml, opts);
|
|
692
|
+
let res = await this.isValidXml(samlContent).catch((error) => {
|
|
693
|
+
return Promise.reject('ERR_EXCEPTION_VALIDATE_XML');
|
|
694
|
+
});
|
|
695
|
+
if (res !== true) {
|
|
696
|
+
return Promise.reject('ERR_EXCEPTION_VALIDATE_XML');
|
|
697
|
+
}
|
|
843
698
|
samlContent = result[0];
|
|
844
699
|
assertionContent = result[1];
|
|
845
700
|
decrypted = true;
|
|
@@ -863,6 +718,7 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
863
718
|
status = (!isMessageSigned || MessageSignatureStatus) &&
|
|
864
719
|
(!isAssertionSigned || AssertionSignatureStatus) &&
|
|
865
720
|
(!encrypted || decrypted);
|
|
721
|
+
// 最终检测不安全的签名算法
|
|
866
722
|
return {
|
|
867
723
|
isMessageSigned,
|
|
868
724
|
MessageSignatureStatus,
|
|
@@ -873,7 +729,9 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
873
729
|
type, // 添加类型字段
|
|
874
730
|
status,
|
|
875
731
|
samlContent,
|
|
876
|
-
assertionContent
|
|
732
|
+
assertionContent,
|
|
733
|
+
hasUnsafeSignatureAlgorithm,
|
|
734
|
+
unsafeSignatureAlgorithm
|
|
877
735
|
};
|
|
878
736
|
},
|
|
879
737
|
verifySignatureSoap(xml, opts) {
|
|
@@ -939,6 +797,8 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
939
797
|
for (const signatureNode of selection) {
|
|
940
798
|
const sig = new SignedXml();
|
|
941
799
|
let verified = false;
|
|
800
|
+
// 检测不安全的签名算法
|
|
801
|
+
const { hasUnsafeSignatureAlgorithm, unsafeSignatureAlgorithm } = checkUnsafeSignatureAlgorithm(opts.signatureAlgorithm || '');
|
|
942
802
|
sig.signatureAlgorithm = opts.signatureAlgorithm;
|
|
943
803
|
if (!opts.keyFile && !opts.metadata) {
|
|
944
804
|
throw new Error('ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS');
|
|
@@ -991,25 +851,25 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
991
851
|
// @ts-expect-error
|
|
992
852
|
const assertions = select("./*[local-name()='Assertion']", rootNode);
|
|
993
853
|
if (encryptedAssert.length === 1) {
|
|
994
|
-
return [true, encryptedAssert[0].toString(), true, false];
|
|
854
|
+
return [true, encryptedAssert[0].toString(), true, false, hasUnsafeSignatureAlgorithm, unsafeSignatureAlgorithm];
|
|
995
855
|
}
|
|
996
856
|
if (assertions.length === 1) {
|
|
997
|
-
return [true, assertions[0].toString(), false, false];
|
|
857
|
+
return [true, assertions[0].toString(), false, false, hasUnsafeSignatureAlgorithm, unsafeSignatureAlgorithm];
|
|
998
858
|
}
|
|
999
|
-
return [true, null, false, true]; // 签名验证成功但未找到断言
|
|
859
|
+
return [true, null, false, true, hasUnsafeSignatureAlgorithm, unsafeSignatureAlgorithm]; // 签名验证成功但未找到断言
|
|
1000
860
|
case 'Assertion':
|
|
1001
|
-
return [true, rootNode.toString(), false, false];
|
|
861
|
+
return [true, rootNode.toString(), false, false, hasUnsafeSignatureAlgorithm, unsafeSignatureAlgorithm];
|
|
1002
862
|
case 'EncryptedAssertion':
|
|
1003
|
-
return [true, rootNode.toString(), true, false];
|
|
863
|
+
return [true, rootNode.toString(), true, false, hasUnsafeSignatureAlgorithm, unsafeSignatureAlgorithm];
|
|
1004
864
|
case 'ArtifactResolve':
|
|
1005
865
|
case 'ArtifactResponse':
|
|
1006
866
|
// 提取SOAP消息内部的实际内容
|
|
1007
|
-
return [true, rootNode.toString(), false, false];
|
|
867
|
+
return [true, rootNode.toString(), false, false, hasUnsafeSignatureAlgorithm, unsafeSignatureAlgorithm];
|
|
1008
868
|
default:
|
|
1009
|
-
return [true, null, false, true]; // 签名验证成功但未找到可识别的内容
|
|
869
|
+
return [true, null, false, true, hasUnsafeSignatureAlgorithm, unsafeSignatureAlgorithm]; // 签名验证成功但未找到可识别的内容
|
|
1010
870
|
}
|
|
1011
871
|
}
|
|
1012
|
-
return [false, null, encryptedAssertions.length > 0, false];
|
|
872
|
+
return [false, null, encryptedAssertions.length > 0, false, false, null];
|
|
1013
873
|
},
|
|
1014
874
|
/**
|
|
1015
875
|
* @desc Helper function to create the key section in metadata (abstraction for signing and encrypt use)
|
|
@@ -1239,6 +1099,8 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
1239
1099
|
if (!decryptedResult) {
|
|
1240
1100
|
throw new Error('ERR_UNDEFINED_DECRYPTED_ASSERTION');
|
|
1241
1101
|
}
|
|
1102
|
+
let hasUnsafeSignatureAlgorithm = false;
|
|
1103
|
+
let unsafeSignatureAlgorithm = "";
|
|
1242
1104
|
// 解密完成后,检查解密后的断言是否还有签名需要验证
|
|
1243
1105
|
const decryptedAssertionDoc = dom.parseFromString(decryptedResult, 'application/xml');
|
|
1244
1106
|
let AssertionSignatureStatus = false;
|
|
@@ -1248,6 +1110,11 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
1248
1110
|
if (assertionSignatureNode.length > 0 && opts) {
|
|
1249
1111
|
// 解密后的断言有签名,需要验证
|
|
1250
1112
|
const signatureNode = assertionSignatureNode[0];
|
|
1113
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
1114
|
+
const signatureAlgorithm = xpath.select1(".//*[local-name(.)='SignatureMethod']/@Algorithm", signatureNode);
|
|
1115
|
+
let checkResult = checkUnsafeSignatureAlgorithm(signatureAlgorithm.value || '');
|
|
1116
|
+
hasUnsafeSignatureAlgorithm = checkResult.hasUnsafeSignatureAlgorithm;
|
|
1117
|
+
unsafeSignatureAlgorithm = checkResult.unsafeSignatureAlgorithm ?? "";
|
|
1251
1118
|
const sig = new SignedXml();
|
|
1252
1119
|
if (!opts.keyFile && !opts.metadata) {
|
|
1253
1120
|
throw new Error('ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS');
|
|
@@ -1281,6 +1148,10 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
1281
1148
|
sig.publicCert = this.getKeyInfo(metadataCert[0]).getKey();
|
|
1282
1149
|
}
|
|
1283
1150
|
}
|
|
1151
|
+
// 检测不安全的签名算法
|
|
1152
|
+
let checkSafeResult = checkUnsafeSignatureAlgorithm(opts.signatureAlgorithm || '');
|
|
1153
|
+
hasUnsafeSignatureAlgorithm = checkSafeResult.hasUnsafeSignatureAlgorithm;
|
|
1154
|
+
unsafeSignatureAlgorithm = checkSafeResult.unsafeSignatureAlgorithm ?? "";
|
|
1284
1155
|
sig.signatureAlgorithm = opts.signatureAlgorithm;
|
|
1285
1156
|
// @ts-expect-error misssing Node properties are not needed
|
|
1286
1157
|
sig.loadSignature(signatureNode);
|
|
@@ -1288,8 +1159,6 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
1288
1159
|
const assertionDocForVerification = dom.parseFromString(decryptedResult, 'application/xml');
|
|
1289
1160
|
const assertionValid = sig.checkSignature(assertionDocForVerification.toString());
|
|
1290
1161
|
AssertionSignatureStatus = assertionValid;
|
|
1291
|
-
console.log(AssertionSignatureStatus);
|
|
1292
|
-
console.log("验证通过了====");
|
|
1293
1162
|
if (!assertionValid) {
|
|
1294
1163
|
throw new Error('ERR_FAILED_TO_VERIFY_DECRYPTED_ASSERTION_SIGNATURE');
|
|
1295
1164
|
}
|
|
@@ -1300,7 +1169,9 @@ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="{ID}"
|
|
|
1300
1169
|
doc.documentElement.replaceChild(rawAssertionDoc.documentElement, encAssertionNode);
|
|
1301
1170
|
return [doc.toString(), decryptedResult, {
|
|
1302
1171
|
isAssertionSigned: !!(assertionSignatureNode.length > 0 && opts),
|
|
1303
|
-
AssertionSignatureStatus: AssertionSignatureStatus
|
|
1172
|
+
AssertionSignatureStatus: AssertionSignatureStatus,
|
|
1173
|
+
hasUnsafeSignatureAlgorithm,
|
|
1174
|
+
unsafeSignatureAlgorithm
|
|
1304
1175
|
}];
|
|
1305
1176
|
},
|
|
1306
1177
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "samlesa",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.4",
|
|
4
4
|
"description": "High-level API for Single Sign On (SAML 2.0) baseed on samlify ",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -43,35 +43,35 @@
|
|
|
43
43
|
"license": "MIT",
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@xmldom/xmldom": "^0.9.8",
|
|
46
|
-
"axios": "^1.
|
|
47
|
-
"camelcase": "^
|
|
48
|
-
"cross-env": "^
|
|
49
|
-
"iconv-lite": "^0.
|
|
46
|
+
"axios": "^1.13.5",
|
|
47
|
+
"camelcase": "^9.0.0",
|
|
48
|
+
"cross-env": "^10.1.0",
|
|
49
|
+
"iconv-lite": "^0.7.2",
|
|
50
50
|
"node-rsa": "^1.1.1",
|
|
51
51
|
"pako": "^2.1.0",
|
|
52
52
|
"ts-node": "^10.9.2",
|
|
53
|
-
"uuid": "^
|
|
54
|
-
"vite-tsconfig-paths": "^
|
|
53
|
+
"uuid": "^13.0.0",
|
|
54
|
+
"vite-tsconfig-paths": "^6.1.1",
|
|
55
55
|
"xml": "^1.0.1",
|
|
56
56
|
"xml-crypto": "^6.1.2",
|
|
57
57
|
"xml-encryption": "^3.1.0",
|
|
58
58
|
"xml-escape": "^1.1.0",
|
|
59
59
|
"xml2js": "^0.6.2",
|
|
60
|
-
"xmllint-wasm": "^5.
|
|
60
|
+
"xmllint-wasm": "^5.1.0",
|
|
61
61
|
"xpath": "^0.0.32"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@types/node": "^
|
|
65
|
-
"@types/pako": "2.0.
|
|
66
|
-
"@types/uuid": "
|
|
67
|
-
"@vitest/coverage-istanbul": "^
|
|
68
|
-
"@vitest/coverage-v8": "
|
|
64
|
+
"@types/node": "^25.3.2",
|
|
65
|
+
"@types/pako": "2.0.4",
|
|
66
|
+
"@types/uuid": "11.0.0",
|
|
67
|
+
"@vitest/coverage-istanbul": "^4.0.18",
|
|
68
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
69
69
|
"copyfiles": "^2.4.1",
|
|
70
70
|
"coveralls": "^3.1.1",
|
|
71
|
-
"esbuild": "^0.
|
|
72
|
-
"jsdom": "^
|
|
71
|
+
"esbuild": "^0.27.3",
|
|
72
|
+
"jsdom": "^28.1.0",
|
|
73
73
|
"timekeeper": "^2.3.1",
|
|
74
|
-
"typescript": "5.
|
|
75
|
-
"vitest": "^
|
|
74
|
+
"typescript": "5.9.3",
|
|
75
|
+
"vitest": "^4.0.18"
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/extractor.ts"],"names":[],"mappings":"AAKA,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC;IACjC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,EAAE,CAAC;AA4B/C,eAAO,MAAM,kBAAkB,EAAE,eA2BhC,CAAC;AACF,eAAO,MAAM,qBAAqB;;;;;;;;;;IAiBjC,CAAC;AACF,eAAO,MAAM,sBAAsB;;;;;;;;;;IAiBlC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;GAWrC,CAAC;AAEF,eAAO,MAAM,iCAAiC;;;;GAW7C,CAAC;AAGF,eAAO,MAAM,0BAA0B;;;;GAWtC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/extractor.ts"],"names":[],"mappings":"AAKA,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC;IACjC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,EAAE,CAAC;AA4B/C,eAAO,MAAM,kBAAkB,EAAE,eA2BhC,CAAC;AACF,eAAO,MAAM,qBAAqB;;;;;;;;;;IAiBjC,CAAC;AACF,eAAO,MAAM,sBAAsB;;;;;;;;;;IAiBlC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;GAWrC,CAAC;AAEF,eAAO,MAAM,iCAAiC;;;;GAW7C,CAAC;AAGF,eAAO,MAAM,0BAA0B;;;;GAWtC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,KAAK,eAAe,CAkErE,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,eA2BjC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAiBlC,CAAC;AAEF,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAA,OA6M9C"}
|
package/types/src/flow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../../src/flow.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,UAAU;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../../src/flow.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,UAAU;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAitBD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BhG;AAED,wBAAgB,IAAI,CAAC,OAAO,KAAA,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BjD"}
|
package/types/src/libsaml.d.ts
CHANGED
|
@@ -136,6 +136,10 @@ declare const _default: {
|
|
|
136
136
|
xml: string;
|
|
137
137
|
error: null;
|
|
138
138
|
};
|
|
139
|
+
checkUnsafeSignatureAlgorithm: (signatureAlgorithm: string) => {
|
|
140
|
+
hasUnsafeSignatureAlgorithm: boolean;
|
|
141
|
+
unsafeSignatureAlgorithm: string | null;
|
|
142
|
+
};
|
|
139
143
|
/**
|
|
140
144
|
* @desc Replace the tag (e.g. {tag}) inside the raw XML
|
|
141
145
|
* @param {string} rawXML raw XML string used to do keyword replacement
|
|
@@ -156,7 +160,7 @@ declare const _default: {
|
|
|
156
160
|
* @desc Construct the XML signature for POST binding
|
|
157
161
|
* @param {string} rawSamlMessage request/response xml string
|
|
158
162
|
* @param {string} referenceTagXPath reference uri
|
|
159
|
-
* @param {string} privateKey declares the private key
|
|
163
|
+
* @param {string} privateKey declares the private key-
|
|
160
164
|
* @param {string} passphrase passphrase of the private key [optional]
|
|
161
165
|
* @param {string|buffer} signingCert signing certificate
|
|
162
166
|
* @param {string} signatureAlgorithm signature algorithm
|
|
@@ -168,7 +172,7 @@ declare const _default: {
|
|
|
168
172
|
isValid: boolean;
|
|
169
173
|
subject: string;
|
|
170
174
|
issuer: string;
|
|
171
|
-
publicKey: import("crypto").KeyObject;
|
|
175
|
+
publicKey: import("node:crypto").KeyObject;
|
|
172
176
|
error?: undefined;
|
|
173
177
|
} | {
|
|
174
178
|
isValid: boolean;
|
|
@@ -177,15 +181,6 @@ declare const _default: {
|
|
|
177
181
|
issuer?: undefined;
|
|
178
182
|
publicKey?: undefined;
|
|
179
183
|
};
|
|
180
|
-
/**
|
|
181
|
-
* @desc Verify the XML signature
|
|
182
|
-
* @param {string} xml xml
|
|
183
|
-
* @param {SignatureVerifierOptions} opts cert declares the X509 certificate
|
|
184
|
-
* @return {[boolean, string | null]} - A tuple where:
|
|
185
|
-
* - The first element is `true` if the signature is valid, `false` otherwise.
|
|
186
|
-
* - The second element is the cryptographically authenticated assertion node as a string, or `null` if not found.
|
|
187
|
-
*/
|
|
188
|
-
verifySignature1(xml: string, opts: SignatureVerifierOptions): (boolean | null)[] | (string | boolean)[];
|
|
189
184
|
/**
|
|
190
185
|
* 改进的SAML签名验证函数,支持多种签名和加密组合场景
|
|
191
186
|
* @param xml SAML XML内容
|
|
@@ -193,14 +188,7 @@ declare const _default: {
|
|
|
193
188
|
* @param self
|
|
194
189
|
* @returns 验证结果对象
|
|
195
190
|
*/
|
|
196
|
-
|
|
197
|
-
* 改进的SAML签名验证函数,支持多种签名和加密组合场景
|
|
198
|
-
* @param xml SAML XML内容
|
|
199
|
-
* @param opts 验证选项
|
|
200
|
-
* @param self
|
|
201
|
-
* @returns 验证结果对象
|
|
202
|
-
*/
|
|
203
|
-
verifySignature(xml: string, opts: SignatureVerifierOptions, self: any): {
|
|
191
|
+
verifySignature(xml: string, opts: SignatureVerifierOptions, self: any): Promise<{
|
|
204
192
|
isMessageSigned: boolean;
|
|
205
193
|
MessageSignatureStatus: boolean;
|
|
206
194
|
isAssertionSigned: boolean;
|
|
@@ -211,8 +199,10 @@ declare const _default: {
|
|
|
211
199
|
status: boolean;
|
|
212
200
|
samlContent: string;
|
|
213
201
|
assertionContent: null;
|
|
214
|
-
|
|
215
|
-
|
|
202
|
+
hasUnsafeSignatureAlgorithm: boolean;
|
|
203
|
+
unsafeSignatureAlgorithm: string;
|
|
204
|
+
}>;
|
|
205
|
+
verifySignatureSoap(xml: string, opts: SignatureVerifierOptions): (string | boolean | null)[];
|
|
216
206
|
/**
|
|
217
207
|
* @desc Helper function to create the key section in metadata (abstraction for signing and encrypt use)
|
|
218
208
|
* @param {string} use type of certificate (e.g. signing, encrypt)
|
|
@@ -274,6 +264,8 @@ declare const _default: {
|
|
|
274
264
|
decryptAssertionSync(here: any, entireXML: string, opts?: SignatureVerifierOptions): (string | {
|
|
275
265
|
isAssertionSigned: boolean;
|
|
276
266
|
AssertionSignatureStatus: boolean;
|
|
267
|
+
hasUnsafeSignatureAlgorithm: boolean;
|
|
268
|
+
unsafeSignatureAlgorithm: string;
|
|
277
269
|
})[];
|
|
278
270
|
/**
|
|
279
271
|
* 解密 SOAP 响应中的加密断言
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libsaml.d.ts","sourceRoot":"","sources":["../../src/libsaml.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"libsaml.d.ts","sourceRoot":"","sources":["../../src/libsaml.ts"],"names":[],"mappings":"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"}
|
package/types/src/utility.d.ts
CHANGED
|
@@ -101,7 +101,7 @@ declare function applyDefault(obj1: any, obj2: any): any;
|
|
|
101
101
|
* @param {string} x509 certificate
|
|
102
102
|
* @return {string} public key fetched from the certificate
|
|
103
103
|
*/
|
|
104
|
-
declare function getPublicKeyPemFromCertificate(x509CertificateString: string): string
|
|
104
|
+
declare function getPublicKeyPemFromCertificate(x509CertificateString: string): string;
|
|
105
105
|
export declare function readPrivateKey(keyString: string | Buffer, passphrase?: string, isOutputString?: boolean): string | Buffer;
|
|
106
106
|
/**
|
|
107
107
|
* @desc Inline syntax sugar
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utility.d.ts","sourceRoot":"","sources":["../../src/utility.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,cAAc,UAAO,MAmB3E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,OAIvC;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,OAEhC;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,YAGnC;AAED;;;;;;GAMG;AACH,wBAAgB,GAAG,CAAC,GAAG,KAAA,EAAE,IAAI,KAAA,EAAE,YAAY,KAAA,OAG1C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,GAAG,mBAElC;AAED;;;;GAIG;AACH,iBAAS,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,UAE/C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAGtF;AAED;;;;GAIG;AACH,iBAAS,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAa9D;AAYD;;;;GAIG;AACH,iBAAS,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,UAEtD;AAED;;;;GAIG;AACH,iBAAS,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,UAErD;AAED;;;;GAIG;AACH,iBAAS,UAAU,CAAC,GAAG,KAAA,UAEtB;AAED;;;;GAIG;AACH,iBAAS,WAAW,CAAC,GAAG,KAAA,EAAE,YAAY,SAAK,OAE1C;AAED;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,IAAI,KAAA,EAAE,IAAI,KAAA,OAE/B;AAED;;;;GAIG;AACH,iBAAS,8BAA8B,CAAC,qBAAqB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"utility.d.ts","sourceRoot":"","sources":["../../src/utility.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,cAAc,UAAO,MAmB3E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,OAIvC;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,OAEhC;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,YAGnC;AAED;;;;;;GAMG;AACH,wBAAgB,GAAG,CAAC,GAAG,KAAA,EAAE,IAAI,KAAA,EAAE,YAAY,KAAA,OAG1C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,GAAG,mBAElC;AAED;;;;GAIG;AACH,iBAAS,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,UAE/C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAGtF;AAED;;;;GAIG;AACH,iBAAS,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAa9D;AAYD;;;;GAIG;AACH,iBAAS,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,UAEtD;AAED;;;;GAIG;AACH,iBAAS,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,UAErD;AAED;;;;GAIG;AACH,iBAAS,UAAU,CAAC,GAAG,KAAA,UAEtB;AAED;;;;GAIG;AACH,iBAAS,WAAW,CAAC,GAAG,KAAA,EAAE,YAAY,SAAK,OAE1C;AAED;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,IAAI,KAAA,EAAE,IAAI,KAAA,OAE/B;AAED;;;;GAIG;AACH,iBAAS,8BAA8B,CAAC,qBAAqB,EAAE,MAAM,UAWpE;AAqCD,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,UAAU,CAAC,EAAE,MAAM,EACnB,cAAc,GAAE,OAAc,GAC7B,MAAM,GAAG,MAAM,CA4BjB;AAGD;;GAEG;AACH,iBAAS,eAAe,CAAC,KAAK,KAAA,EAAE,cAAc,KAAA,OAE7C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,WAErC;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,CAGhD;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,CAElF;AAED,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;CAeZ,CAAC;AAEF,eAAe,OAAO,CAAC"}
|