@wirebench/engine 2.1.1
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/LICENSE +201 -0
- package/README.md +3 -0
- package/dist/assert/contract.d.ts +3 -0
- package/dist/assert/contract.js +17 -0
- package/dist/assert/index.d.ts +4 -0
- package/dist/assert/index.js +27 -0
- package/dist/assert/match.d.ts +3 -0
- package/dist/assert/match.js +58 -0
- package/dist/assert/model.d.ts +73 -0
- package/dist/assert/model.js +8 -0
- package/dist/assert/schema.d.ts +34 -0
- package/dist/assert/schema.js +46 -0
- package/dist/assert/sla.d.ts +3 -0
- package/dist/assert/sla.js +8 -0
- package/dist/assert/soap-fault.d.ts +3 -0
- package/dist/assert/soap-fault.js +20 -0
- package/dist/assert/status.d.ts +3 -0
- package/dist/assert/status.js +14 -0
- package/dist/errors.d.ts +77 -0
- package/dist/errors.js +121 -0
- package/dist/fs.d.ts +35 -0
- package/dist/fs.js +64 -0
- package/dist/generate.d.ts +12 -0
- package/dist/generate.js +14 -0
- package/dist/grpc/browser.d.ts +11 -0
- package/dist/grpc/browser.js +9 -0
- package/dist/grpc/cache.d.ts +113 -0
- package/dist/grpc/cache.js +244 -0
- package/dist/grpc/call.d.ts +64 -0
- package/dist/grpc/call.js +72 -0
- package/dist/grpc/codec.d.ts +29 -0
- package/dist/grpc/codec.js +416 -0
- package/dist/grpc/command.d.ts +23 -0
- package/dist/grpc/command.js +91 -0
- package/dist/grpc/expand.d.ts +25 -0
- package/dist/grpc/expand.js +52 -0
- package/dist/grpc/framing.d.ts +28 -0
- package/dist/grpc/framing.js +61 -0
- package/dist/grpc/import.d.ts +47 -0
- package/dist/grpc/import.js +88 -0
- package/dist/grpc/model.d.ts +179 -0
- package/dist/grpc/model.js +91 -0
- package/dist/grpc/proto/describe.d.ts +92 -0
- package/dist/grpc/proto/describe.js +205 -0
- package/dist/grpc/proto/load.d.ts +35 -0
- package/dist/grpc/proto/load.js +112 -0
- package/dist/grpc/proto/sample.d.ts +21 -0
- package/dist/grpc/proto/sample.js +79 -0
- package/dist/grpc/proto/well-known.d.ts +42 -0
- package/dist/grpc/proto/well-known.js +143 -0
- package/dist/grpc/reconcile.d.ts +42 -0
- package/dist/grpc/reconcile.js +153 -0
- package/dist/grpc/reflection/client.d.ts +70 -0
- package/dist/grpc/reflection/client.js +197 -0
- package/dist/grpc/reflection/descriptors.d.ts +69 -0
- package/dist/grpc/reflection/descriptors.js +140 -0
- package/dist/grpc/reflection/proto.d.ts +33 -0
- package/dist/grpc/reflection/proto.js +144 -0
- package/dist/grpc/send.d.ts +132 -0
- package/dist/grpc/send.js +435 -0
- package/dist/grpc/shape.d.ts +29 -0
- package/dist/grpc/shape.js +36 -0
- package/dist/grpc/status.d.ts +21 -0
- package/dist/grpc/status.js +62 -0
- package/dist/grpc/target.d.ts +21 -0
- package/dist/grpc/target.js +66 -0
- package/dist/http/auth/apply.d.ts +37 -0
- package/dist/http/auth/apply.js +74 -0
- package/dist/http/auth/basic.d.ts +36 -0
- package/dist/http/auth/basic.js +69 -0
- package/dist/http/auth/md4.d.ts +13 -0
- package/dist/http/auth/md4.js +81 -0
- package/dist/http/auth/ntlm-transport.d.ts +61 -0
- package/dist/http/auth/ntlm-transport.js +97 -0
- package/dist/http/auth/ntlm.d.ts +190 -0
- package/dist/http/auth/ntlm.js +377 -0
- package/dist/http/client.d.ts +73 -0
- package/dist/http/client.js +403 -0
- package/dist/http/curl-flags.d.ts +15 -0
- package/dist/http/curl-flags.js +95 -0
- package/dist/http/curl.d.ts +94 -0
- package/dist/http/curl.js +245 -0
- package/dist/http/decompress.d.ts +7 -0
- package/dist/http/decompress.js +22 -0
- package/dist/http/errors.d.ts +22 -0
- package/dist/http/errors.js +144 -0
- package/dist/http/failed-request.d.ts +27 -0
- package/dist/http/failed-request.js +48 -0
- package/dist/http/headers.d.ts +15 -0
- package/dist/http/headers.js +50 -0
- package/dist/http/heredoc.d.ts +25 -0
- package/dist/http/heredoc.js +74 -0
- package/dist/http/proxy.d.ts +103 -0
- package/dist/http/proxy.js +168 -0
- package/dist/http/raw-capture.d.ts +23 -0
- package/dist/http/raw-capture.js +57 -0
- package/dist/http/timings.d.ts +79 -0
- package/dist/http/timings.js +212 -0
- package/dist/http/tls.d.ts +111 -0
- package/dist/http/tls.js +167 -0
- package/dist/http/types.d.ts +125 -0
- package/dist/http/types.js +6 -0
- package/dist/import-detect.d.ts +26 -0
- package/dist/import-detect.js +169 -0
- package/dist/import.d.ts +20 -0
- package/dist/import.js +163 -0
- package/dist/index.d.ts +272 -0
- package/dist/index.js +157 -0
- package/dist/json/cursor.d.ts +43 -0
- package/dist/json/cursor.js +168 -0
- package/dist/operations.d.ts +12 -0
- package/dist/operations.js +52 -0
- package/dist/project/attachments-cache.d.ts +80 -0
- package/dist/project/attachments-cache.js +186 -0
- package/dist/project/endpoints.d.ts +23 -0
- package/dist/project/endpoints.js +47 -0
- package/dist/project/environments.d.ts +68 -0
- package/dist/project/environments.js +124 -0
- package/dist/project/fs.d.ts +45 -0
- package/dist/project/fs.js +78 -0
- package/dist/project/history.d.ts +171 -0
- package/dist/project/history.js +179 -0
- package/dist/project/keystores.d.ts +24 -0
- package/dist/project/keystores.js +66 -0
- package/dist/project/load.d.ts +44 -0
- package/dist/project/load.js +634 -0
- package/dist/project/migrate.d.ts +27 -0
- package/dist/project/migrate.js +46 -0
- package/dist/project/model.d.ts +401 -0
- package/dist/project/model.js +126 -0
- package/dist/project/paths.d.ts +134 -0
- package/dist/project/paths.js +259 -0
- package/dist/project/preferences.d.ts +318 -0
- package/dist/project/preferences.js +239 -0
- package/dist/project/properties.d.ts +97 -0
- package/dist/project/properties.js +356 -0
- package/dist/project/save.d.ts +65 -0
- package/dist/project/save.js +295 -0
- package/dist/project/schema.d.ts +1329 -0
- package/dist/project/schema.js +737 -0
- package/dist/project/serialize.d.ts +42 -0
- package/dist/project/serialize.js +385 -0
- package/dist/project/wss-configs.d.ts +40 -0
- package/dist/project/wss-configs.js +142 -0
- package/dist/project/yaml.d.ts +17 -0
- package/dist/project/yaml.js +39 -0
- package/dist/redact/index.d.ts +77 -0
- package/dist/redact/index.js +328 -0
- package/dist/redact/literal.d.ts +12 -0
- package/dist/redact/literal.js +68 -0
- package/dist/rest/auth.d.ts +53 -0
- package/dist/rest/auth.js +80 -0
- package/dist/rest/body.d.ts +61 -0
- package/dist/rest/body.js +184 -0
- package/dist/rest/browser.d.ts +12 -0
- package/dist/rest/browser.js +11 -0
- package/dist/rest/cookies.d.ts +41 -0
- package/dist/rest/cookies.js +102 -0
- package/dist/rest/curl.d.ts +75 -0
- package/dist/rest/curl.js +417 -0
- package/dist/rest/expand.d.ts +35 -0
- package/dist/rest/expand.js +104 -0
- package/dist/rest/model.d.ts +247 -0
- package/dist/rest/model.js +118 -0
- package/dist/rest/oauth2.d.ts +118 -0
- package/dist/rest/oauth2.js +212 -0
- package/dist/rest/openapi/cache.d.ts +54 -0
- package/dist/rest/openapi/cache.js +128 -0
- package/dist/rest/openapi/import.d.ts +67 -0
- package/dist/rest/openapi/import.js +91 -0
- package/dist/rest/openapi/map.d.ts +102 -0
- package/dist/rest/openapi/map.js +477 -0
- package/dist/rest/openapi/model.d.ts +203 -0
- package/dist/rest/openapi/model.js +37 -0
- package/dist/rest/openapi/parse.d.ts +44 -0
- package/dist/rest/openapi/parse.js +1530 -0
- package/dist/rest/openapi/refs.d.ts +63 -0
- package/dist/rest/openapi/refs.js +258 -0
- package/dist/rest/openapi/sample.d.ts +68 -0
- package/dist/rest/openapi/sample.js +336 -0
- package/dist/rest/postman/import.d.ts +21 -0
- package/dist/rest/postman/import.js +47 -0
- package/dist/rest/postman/index.d.ts +7 -0
- package/dist/rest/postman/index.js +7 -0
- package/dist/rest/postman/map.d.ts +28 -0
- package/dist/rest/postman/map.js +427 -0
- package/dist/rest/postman/model.d.ts +118 -0
- package/dist/rest/postman/model.js +7 -0
- package/dist/rest/postman/parse.d.ts +29 -0
- package/dist/rest/postman/parse.js +518 -0
- package/dist/rest/response.d.ts +72 -0
- package/dist/rest/response.js +221 -0
- package/dist/rest/send.d.ts +102 -0
- package/dist/rest/send.js +148 -0
- package/dist/rest/url.d.ts +92 -0
- package/dist/rest/url.js +213 -0
- package/dist/run/effective-auth.d.ts +10 -0
- package/dist/run/effective-auth.js +19 -0
- package/dist/run/index.d.ts +8 -0
- package/dist/run/index.js +4 -0
- package/dist/run/prepare.d.ts +43 -0
- package/dist/run/prepare.js +280 -0
- package/dist/run/run.d.ts +53 -0
- package/dist/run/run.js +223 -0
- package/dist/run/secret-needs.d.ts +13 -0
- package/dist/run/secret-needs.js +125 -0
- package/dist/run/select.d.ts +34 -0
- package/dist/run/select.js +76 -0
- package/dist/secrets/env-names.d.ts +27 -0
- package/dist/secrets/env-names.js +40 -0
- package/dist/secrets/resolve.d.ts +58 -0
- package/dist/secrets/resolve.js +136 -0
- package/dist/send-options.d.ts +141 -0
- package/dist/send-options.js +228 -0
- package/dist/send.d.ts +53 -0
- package/dist/send.js +210 -0
- package/dist/soap/body-builder.d.ts +38 -0
- package/dist/soap/body-builder.js +250 -0
- package/dist/soap/build-problems.d.ts +12 -0
- package/dist/soap/build-problems.js +2 -0
- package/dist/soap/charset.d.ts +23 -0
- package/dist/soap/charset.js +47 -0
- package/dist/soap/envelope.d.ts +44 -0
- package/dist/soap/envelope.js +76 -0
- package/dist/soap/fault.d.ts +46 -0
- package/dist/soap/fault.js +129 -0
- package/dist/soap/form-request.d.ts +34 -0
- package/dist/soap/form-request.js +251 -0
- package/dist/soap/legacy-project/definition-fetcher.d.ts +21 -0
- package/dist/soap/legacy-project/definition-fetcher.js +43 -0
- package/dist/soap/legacy-project/format.d.ts +18 -0
- package/dist/soap/legacy-project/format.js +24 -0
- package/dist/soap/legacy-project/import.d.ts +21 -0
- package/dist/soap/legacy-project/import.js +46 -0
- package/dist/soap/legacy-project/index.d.ts +9 -0
- package/dist/soap/legacy-project/index.js +5 -0
- package/dist/soap/legacy-project/map.d.ts +91 -0
- package/dist/soap/legacy-project/map.js +290 -0
- package/dist/soap/legacy-project/model.d.ts +98 -0
- package/dist/soap/legacy-project/model.js +5 -0
- package/dist/soap/legacy-project/parse.d.ts +16 -0
- package/dist/soap/legacy-project/parse.js +325 -0
- package/dist/soap/mime/cid-scan.d.ts +36 -0
- package/dist/soap/mime/cid-scan.js +52 -0
- package/dist/soap/mime/inline-files.d.ts +39 -0
- package/dist/soap/mime/inline-files.js +71 -0
- package/dist/soap/mime/mtom.d.ts +74 -0
- package/dist/soap/mime/mtom.js +134 -0
- package/dist/soap/mime/multipart.d.ts +66 -0
- package/dist/soap/mime/multipart.js +329 -0
- package/dist/soap/mime/send-pipeline.d.ts +61 -0
- package/dist/soap/mime/send-pipeline.js +145 -0
- package/dist/soap/mime/swa.d.ts +45 -0
- package/dist/soap/mime/swa.js +62 -0
- package/dist/soap/mime/types.d.ts +69 -0
- package/dist/soap/mime/types.js +10 -0
- package/dist/soap/namespace-scope.d.ts +32 -0
- package/dist/soap/namespace-scope.js +85 -0
- package/dist/soap/prefixes.d.ts +24 -0
- package/dist/soap/prefixes.js +70 -0
- package/dist/soap/recreate.d.ts +28 -0
- package/dist/soap/recreate.js +168 -0
- package/dist/soap/request-builder.d.ts +63 -0
- package/dist/soap/request-builder.js +161 -0
- package/dist/soap/response-parser.d.ts +29 -0
- package/dist/soap/response-parser.js +71 -0
- package/dist/soap/soap-action.d.ts +31 -0
- package/dist/soap/soap-action.js +28 -0
- package/dist/soap/transforms.d.ts +52 -0
- package/dist/soap/transforms.js +164 -0
- package/dist/types.d.ts +307 -0
- package/dist/types.js +6 -0
- package/dist/validate/index.d.ts +61 -0
- package/dist/validate/index.js +72 -0
- package/dist/validate/schema-file-set.d.ts +51 -0
- package/dist/validate/schema-file-set.js +288 -0
- package/dist/validate/schema-validator.d.ts +53 -0
- package/dist/validate/schema-validator.js +251 -0
- package/dist/validate/soap-structure.d.ts +34 -0
- package/dist/validate/soap-structure.js +255 -0
- package/dist/validate/types.d.ts +47 -0
- package/dist/validate/types.js +8 -0
- package/dist/validate/wsi/assertions/helpers.d.ts +145 -0
- package/dist/validate/wsi/assertions/helpers.js +387 -0
- package/dist/validate/wsi/assertions/index.d.ts +44 -0
- package/dist/validate/wsi/assertions/index.js +77 -0
- package/dist/validate/wsi/assertions/message/helpers.d.ts +63 -0
- package/dist/validate/wsi/assertions/message/helpers.js +168 -0
- package/dist/validate/wsi/assertions/message/index.d.ts +39 -0
- package/dist/validate/wsi/assertions/message/index.js +62 -0
- package/dist/validate/wsi/assertions/message/r1001.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1001.js +38 -0
- package/dist/validate/wsi/assertions/message/r1003.d.ts +14 -0
- package/dist/validate/wsi/assertions/message/r1003.js +45 -0
- package/dist/validate/wsi/assertions/message/r1005.d.ts +12 -0
- package/dist/validate/wsi/assertions/message/r1005.js +37 -0
- package/dist/validate/wsi/assertions/message/r1006.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1006.js +49 -0
- package/dist/validate/wsi/assertions/message/r1007.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1007.js +30 -0
- package/dist/validate/wsi/assertions/message/r1011.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1011.js +33 -0
- package/dist/validate/wsi/assertions/message/r1012.d.ts +13 -0
- package/dist/validate/wsi/assertions/message/r1012.js +37 -0
- package/dist/validate/wsi/assertions/message/r1013.d.ts +9 -0
- package/dist/validate/wsi/assertions/message/r1013.js +42 -0
- package/dist/validate/wsi/assertions/message/r1014.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1014.js +30 -0
- package/dist/validate/wsi/assertions/message/r1015.d.ts +12 -0
- package/dist/validate/wsi/assertions/message/r1015.js +36 -0
- package/dist/validate/wsi/assertions/message/r1017.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1017.js +30 -0
- package/dist/validate/wsi/assertions/message/r1100.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1100.js +39 -0
- package/dist/validate/wsi/assertions/message/r1101.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1101.js +37 -0
- package/dist/validate/wsi/assertions/message/r1102.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1102.js +41 -0
- package/dist/validate/wsi/assertions/message/r1103.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1103.js +28 -0
- package/dist/validate/wsi/assertions/message/r1107.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1107.js +38 -0
- package/dist/validate/wsi/assertions/message/r1109.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1109.js +32 -0
- package/dist/validate/wsi/assertions/message/r1124.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1124.js +31 -0
- package/dist/validate/wsi/assertions/message/r1132.d.ts +9 -0
- package/dist/validate/wsi/assertions/message/r1132.js +23 -0
- package/dist/validate/wsi/assertions/message/r1140.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1140.js +42 -0
- package/dist/validate/wsi/assertions/message/r1141.d.ts +10 -0
- package/dist/validate/wsi/assertions/message/r1141.js +32 -0
- package/dist/validate/wsi/assertions/message/r2113.d.ts +11 -0
- package/dist/validate/wsi/assertions/message/r2113.js +33 -0
- package/dist/validate/wsi/assertions/message/r2211.d.ts +7 -0
- package/dist/validate/wsi/assertions/message/r2211.js +42 -0
- package/dist/validate/wsi/assertions/r2001.d.ts +15 -0
- package/dist/validate/wsi/assertions/r2001.js +47 -0
- package/dist/validate/wsi/assertions/r2002.d.ts +11 -0
- package/dist/validate/wsi/assertions/r2002.js +38 -0
- package/dist/validate/wsi/assertions/r2003.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2003.js +32 -0
- package/dist/validate/wsi/assertions/r2005.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2005.js +40 -0
- package/dist/validate/wsi/assertions/r2101.d.ts +14 -0
- package/dist/validate/wsi/assertions/r2101.js +65 -0
- package/dist/validate/wsi/assertions/r2102.d.ts +10 -0
- package/dist/validate/wsi/assertions/r2102.js +41 -0
- package/dist/validate/wsi/assertions/r2105.d.ts +8 -0
- package/dist/validate/wsi/assertions/r2105.js +39 -0
- package/dist/validate/wsi/assertions/r2110.d.ts +8 -0
- package/dist/validate/wsi/assertions/r2110.js +38 -0
- package/dist/validate/wsi/assertions/r2111.d.ts +6 -0
- package/dist/validate/wsi/assertions/r2111.js +30 -0
- package/dist/validate/wsi/assertions/r2112.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2112.js +35 -0
- package/dist/validate/wsi/assertions/r2201.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2201.js +28 -0
- package/dist/validate/wsi/assertions/r2203.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2203.js +30 -0
- package/dist/validate/wsi/assertions/r2204.d.ts +6 -0
- package/dist/validate/wsi/assertions/r2204.js +29 -0
- package/dist/validate/wsi/assertions/r2205.d.ts +8 -0
- package/dist/validate/wsi/assertions/r2205.js +46 -0
- package/dist/validate/wsi/assertions/r2206.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2206.js +36 -0
- package/dist/validate/wsi/assertions/r2209.d.ts +12 -0
- package/dist/validate/wsi/assertions/r2209.js +37 -0
- package/dist/validate/wsi/assertions/r2210.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2210.js +30 -0
- package/dist/validate/wsi/assertions/r2303.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2303.js +44 -0
- package/dist/validate/wsi/assertions/r2304.d.ts +6 -0
- package/dist/validate/wsi/assertions/r2304.js +32 -0
- package/dist/validate/wsi/assertions/r2401.d.ts +12 -0
- package/dist/validate/wsi/assertions/r2401.js +31 -0
- package/dist/validate/wsi/assertions/r2701.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2701.js +28 -0
- package/dist/validate/wsi/assertions/r2702.d.ts +6 -0
- package/dist/validate/wsi/assertions/r2702.js +26 -0
- package/dist/validate/wsi/assertions/r2705.d.ts +11 -0
- package/dist/validate/wsi/assertions/r2705.js +31 -0
- package/dist/validate/wsi/assertions/r2706.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2706.js +29 -0
- package/dist/validate/wsi/assertions/r2710.d.ts +13 -0
- package/dist/validate/wsi/assertions/r2710.js +37 -0
- package/dist/validate/wsi/assertions/r2716.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2716.js +29 -0
- package/dist/validate/wsi/assertions/r2717.d.ts +9 -0
- package/dist/validate/wsi/assertions/r2717.js +31 -0
- package/dist/validate/wsi/assertions/r2718.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2718.js +41 -0
- package/dist/validate/wsi/assertions/r2720.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2720.js +29 -0
- package/dist/validate/wsi/assertions/r2721.d.ts +6 -0
- package/dist/validate/wsi/assertions/r2721.js +27 -0
- package/dist/validate/wsi/assertions/r2722.d.ts +6 -0
- package/dist/validate/wsi/assertions/r2722.js +29 -0
- package/dist/validate/wsi/assertions/r2801.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2801.js +39 -0
- package/dist/validate/wsi/assertions/r2803.d.ts +7 -0
- package/dist/validate/wsi/assertions/r2803.js +29 -0
- package/dist/validate/wsi/docs.d.ts +29 -0
- package/dist/validate/wsi/docs.js +167 -0
- package/dist/validate/wsi/index.d.ts +16 -0
- package/dist/validate/wsi/index.js +11 -0
- package/dist/validate/wsi/report-html.d.ts +36 -0
- package/dist/validate/wsi/report-html.js +135 -0
- package/dist/validate/wsi/run-message.d.ts +50 -0
- package/dist/validate/wsi/run-message.js +190 -0
- package/dist/validate/wsi/run-wsdl.d.ts +48 -0
- package/dist/validate/wsi/run-wsdl.js +99 -0
- package/dist/validate/wsi/types.d.ts +173 -0
- package/dist/validate/wsi/types.js +17 -0
- package/dist/workspace/commit-message.d.ts +47 -0
- package/dist/workspace/commit-message.js +195 -0
- package/dist/workspace/environments.d.ts +79 -0
- package/dist/workspace/environments.js +115 -0
- package/dist/workspace/index.d.ts +28 -0
- package/dist/workspace/index.js +19 -0
- package/dist/workspace/load.d.ts +45 -0
- package/dist/workspace/load.js +155 -0
- package/dist/workspace/local-state.d.ts +37 -0
- package/dist/workspace/local-state.js +59 -0
- package/dist/workspace/migrate.d.ts +38 -0
- package/dist/workspace/migrate.js +50 -0
- package/dist/workspace/model.d.ts +86 -0
- package/dist/workspace/model.js +54 -0
- package/dist/workspace/paths.d.ts +64 -0
- package/dist/workspace/paths.js +97 -0
- package/dist/workspace/reidentify.d.ts +22 -0
- package/dist/workspace/reidentify.js +122 -0
- package/dist/workspace/save.d.ts +31 -0
- package/dist/workspace/save.js +84 -0
- package/dist/workspace/schema.d.ts +93 -0
- package/dist/workspace/schema.js +115 -0
- package/dist/workspace/serialize.d.ts +24 -0
- package/dist/workspace/serialize.js +60 -0
- package/dist/workspace/share.d.ts +52 -0
- package/dist/workspace/share.js +89 -0
- package/dist/ws/browser.d.ts +13 -0
- package/dist/ws/browser.js +11 -0
- package/dist/ws/call.d.ts +53 -0
- package/dist/ws/call.js +106 -0
- package/dist/ws/command.d.ts +19 -0
- package/dist/ws/command.js +28 -0
- package/dist/ws/expand.d.ts +38 -0
- package/dist/ws/expand.js +76 -0
- package/dist/ws/model.d.ts +191 -0
- package/dist/ws/model.js +83 -0
- package/dist/ws/pretty.d.ts +12 -0
- package/dist/ws/pretty.js +25 -0
- package/dist/ws/session.d.ts +50 -0
- package/dist/ws/session.js +333 -0
- package/dist/ws/shape.d.ts +18 -0
- package/dist/ws/shape.js +28 -0
- package/dist/ws/transcript.d.ts +14 -0
- package/dist/ws/transcript.js +29 -0
- package/dist/ws/url.d.ts +3 -0
- package/dist/ws/url.js +44 -0
- package/dist/wsa/headers.d.ts +78 -0
- package/dist/wsa/headers.js +244 -0
- package/dist/wsa/model.d.ts +66 -0
- package/dist/wsa/model.js +52 -0
- package/dist/wsa/policy-detect.d.ts +81 -0
- package/dist/wsa/policy-detect.js +245 -0
- package/dist/wsdl/cache-naming.d.ts +39 -0
- package/dist/wsdl/cache-naming.js +90 -0
- package/dist/wsdl/cache.d.ts +48 -0
- package/dist/wsdl/cache.js +141 -0
- package/dist/wsdl/docs-generator.d.ts +47 -0
- package/dist/wsdl/docs-generator.js +439 -0
- package/dist/wsdl/dom-utils.d.ts +15 -0
- package/dist/wsdl/dom-utils.js +50 -0
- package/dist/wsdl/export-definition.d.ts +38 -0
- package/dist/wsdl/export-definition.js +100 -0
- package/dist/wsdl/fetch.d.ts +13 -0
- package/dist/wsdl/fetch.js +60 -0
- package/dist/wsdl/merge.d.ts +17 -0
- package/dist/wsdl/merge.js +57 -0
- package/dist/wsdl/model.d.ts +176 -0
- package/dist/wsdl/model.js +17 -0
- package/dist/wsdl/parse-binding.d.ts +6 -0
- package/dist/wsdl/parse-binding.js +150 -0
- package/dist/wsdl/parse-wsdl.d.ts +47 -0
- package/dist/wsdl/parse-wsdl.js +161 -0
- package/dist/wsdl/qname.d.ts +28 -0
- package/dist/wsdl/qname.js +41 -0
- package/dist/wsdl/ref-policy.d.ts +54 -0
- package/dist/wsdl/ref-policy.js +87 -0
- package/dist/wsdl/resolver.d.ts +81 -0
- package/dist/wsdl/resolver.js +276 -0
- package/dist/wsdl/update-definition.d.ts +106 -0
- package/dist/wsdl/update-definition.js +314 -0
- package/dist/wss/apply.d.ts +40 -0
- package/dist/wss/apply.js +212 -0
- package/dist/wss/c14n-prefixes.d.ts +27 -0
- package/dist/wss/c14n-prefixes.js +95 -0
- package/dist/wss/incoming/decrypt.d.ts +35 -0
- package/dist/wss/incoming/decrypt.js +57 -0
- package/dist/wss/incoming/index.d.ts +56 -0
- package/dist/wss/incoming/index.js +189 -0
- package/dist/wss/incoming/verify.d.ts +74 -0
- package/dist/wss/incoming/verify.js +440 -0
- package/dist/wss/key-identifiers.d.ts +76 -0
- package/dist/wss/key-identifiers.js +139 -0
- package/dist/wss/keystore/certificate.d.ts +45 -0
- package/dist/wss/keystore/certificate.js +134 -0
- package/dist/wss/keystore/index.d.ts +50 -0
- package/dist/wss/keystore/index.js +80 -0
- package/dist/wss/keystore/model.d.ts +83 -0
- package/dist/wss/keystore/model.js +27 -0
- package/dist/wss/keystore/pem.d.ts +21 -0
- package/dist/wss/keystore/pem.js +140 -0
- package/dist/wss/keystore/pkcs12.d.ts +21 -0
- package/dist/wss/keystore/pkcs12.js +125 -0
- package/dist/wss/model.d.ts +160 -0
- package/dist/wss/model.js +37 -0
- package/dist/wss/outgoing/encryption.d.ts +76 -0
- package/dist/wss/outgoing/encryption.js +618 -0
- package/dist/wss/outgoing/signature.d.ts +73 -0
- package/dist/wss/outgoing/signature.js +239 -0
- package/dist/wss/outgoing/timestamp.d.ts +29 -0
- package/dist/wss/outgoing/timestamp.js +39 -0
- package/dist/wss/outgoing/username-token.d.ts +36 -0
- package/dist/wss/outgoing/username-token.js +68 -0
- package/dist/wss/security-header.d.ts +31 -0
- package/dist/wss/security-header.js +83 -0
- package/dist/xml/index.d.ts +7 -0
- package/dist/xml/index.js +7 -0
- package/dist/xml/namespaces.d.ts +36 -0
- package/dist/xml/namespaces.js +60 -0
- package/dist/xml/parse.d.ts +79 -0
- package/dist/xml/parse.js +109 -0
- package/dist/xml/positions.d.ts +26 -0
- package/dist/xml/positions.js +71 -0
- package/dist/xml/pretty.d.ts +37 -0
- package/dist/xml/pretty.js +137 -0
- package/dist/xml/serialize.d.ts +6 -0
- package/dist/xml/serialize.js +8 -0
- package/dist/xml/tolerant-tree.d.ts +56 -0
- package/dist/xml/tolerant-tree.js +134 -0
- package/dist/xpath/evaluate-async.d.ts +31 -0
- package/dist/xpath/evaluate-async.js +81 -0
- package/dist/xpath/evaluate.d.ts +98 -0
- package/dist/xpath/evaluate.js +340 -0
- package/dist/xpath/jsonpath.d.ts +40 -0
- package/dist/xpath/jsonpath.js +109 -0
- package/dist/xpath/namespaces.d.ts +29 -0
- package/dist/xpath/namespaces.js +101 -0
- package/dist/xpath/worker.d.ts +7 -0
- package/dist/xpath/worker.js +26 -0
- package/dist/xsd/builtins.d.ts +36 -0
- package/dist/xsd/builtins.js +108 -0
- package/dist/xsd/check-references.d.ts +25 -0
- package/dist/xsd/check-references.js +145 -0
- package/dist/xsd/form-edits.d.ts +57 -0
- package/dist/xsd/form-edits.js +153 -0
- package/dist/xsd/form-model.d.ts +153 -0
- package/dist/xsd/form-model.js +691 -0
- package/dist/xsd/locate.d.ts +42 -0
- package/dist/xsd/locate.js +249 -0
- package/dist/xsd/model.d.ts +249 -0
- package/dist/xsd/model.js +1 -0
- package/dist/xsd/parse-particles.d.ts +48 -0
- package/dist/xsd/parse-particles.js +320 -0
- package/dist/xsd/parse-schema.d.ts +21 -0
- package/dist/xsd/parse-schema.js +143 -0
- package/dist/xsd/resolve-content.d.ts +18 -0
- package/dist/xsd/resolve-content.js +242 -0
- package/dist/xsd/sample-generator.d.ts +51 -0
- package/dist/xsd/sample-generator.js +291 -0
- package/dist/xsd/sample-types.d.ts +21 -0
- package/dist/xsd/sample-types.js +69 -0
- package/dist/xsd/sample-values.d.ts +54 -0
- package/dist/xsd/sample-values.js +267 -0
- package/dist/xsd/schema-set.d.ts +51 -0
- package/dist/xsd/schema-set.js +203 -0
- package/dist/xsd/xml-scan.d.ts +64 -0
- package/dist/xsd/xml-scan.js +286 -0
- package/dist/xsd/xml-writer.d.ts +56 -0
- package/dist/xsd/xml-writer.js +103 -0
- package/package.json +69 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification of an *incoming* message: every `ds:Signature` in a `wsse:Security` header, and
|
|
3
|
+
* the header's `wsu:Timestamp`.
|
|
4
|
+
*
|
|
5
|
+
* Two questions are answered separately, because they fail for different reasons and a user
|
|
6
|
+
* has to be able to tell them apart:
|
|
7
|
+
*
|
|
8
|
+
* - **validity** — does the signature actually hold over the bytes that arrived? That is
|
|
9
|
+
* Task 38's {@link verifySignature}, run against the certificate the message's own `KeyInfo`
|
|
10
|
+
* points at.
|
|
11
|
+
* - **trust** — is that certificate one we accept? A signature verifies perfectly against the
|
|
12
|
+
* key that made it, including a key an attacker owns, so the certificate is checked against
|
|
13
|
+
* the configured truststore: stored verbatim, or (with `verifyChain`) chaining to one of its
|
|
14
|
+
* certificates.
|
|
15
|
+
*
|
|
16
|
+
* `KeyInfo` is therefore a *hint* about which key to look up, never a source of trust.
|
|
17
|
+
*/
|
|
18
|
+
import forge from 'node-forge';
|
|
19
|
+
import { NS } from '../../xml/namespaces.js';
|
|
20
|
+
import { parseXml } from '../../xml/parse.js';
|
|
21
|
+
import { serializeXml } from '../../xml/serialize.js';
|
|
22
|
+
import { renderDn, renderDnRfc2253 } from '../keystore/certificate.js';
|
|
23
|
+
import { certificateBase64, subjectKeyIdentifierBase64, thumbprintSha1Base64, WSS_TOKEN_TYPES, } from '../key-identifiers.js';
|
|
24
|
+
import { childElement, findElement } from '../security-header.js';
|
|
25
|
+
import { verifySignature } from '../outgoing/signature.js';
|
|
26
|
+
/** Every descendant-or-self of `root` in `namespace` with local name `localName`, in document order. */
|
|
27
|
+
function findAll(root, namespace, localName) {
|
|
28
|
+
const found = [];
|
|
29
|
+
const walk = (node) => {
|
|
30
|
+
if (node.namespaceURI === namespace && node.localName === localName) {
|
|
31
|
+
found.push(node);
|
|
32
|
+
}
|
|
33
|
+
for (let child = node.firstChild; child !== null; child = child.nextSibling) {
|
|
34
|
+
if (child.nodeType === 1) {
|
|
35
|
+
walk(child);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
walk(root);
|
|
40
|
+
return found;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Every element under `root` by the value of its `Id` attribute (in any namespace, or none),
|
|
44
|
+
* built once per document.
|
|
45
|
+
*
|
|
46
|
+
* A *list* per id rather than the first match: a duplicated id is how a signature-wrapping
|
|
47
|
+
* attack hides a second element behind a reference, so ambiguity has to be visible rather than
|
|
48
|
+
* resolved by document order.
|
|
49
|
+
*/
|
|
50
|
+
function idIndex(root) {
|
|
51
|
+
const index = new Map();
|
|
52
|
+
const walk = (node) => {
|
|
53
|
+
for (let position = 0; position < node.attributes.length; position += 1) {
|
|
54
|
+
const attribute = node.attributes.item(position);
|
|
55
|
+
if (attribute !== null && attribute.localName === 'Id' && attribute.value !== '') {
|
|
56
|
+
const found = index.get(attribute.value);
|
|
57
|
+
if (found === undefined) {
|
|
58
|
+
index.set(attribute.value, [node]);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
found.push(node);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (let child = node.firstChild; child !== null; child = child.nextSibling) {
|
|
66
|
+
if (child.nodeType === 1) {
|
|
67
|
+
walk(child);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
walk(root);
|
|
72
|
+
return index;
|
|
73
|
+
}
|
|
74
|
+
/** The one element carrying `id`, or `undefined` when no element — or more than one — does. */
|
|
75
|
+
function uniqueById(index, id) {
|
|
76
|
+
const found = index.get(id);
|
|
77
|
+
return found?.length === 1 ? found[0] : undefined;
|
|
78
|
+
}
|
|
79
|
+
/** The text of `element` with every whitespace character removed, so wrapped base64 compares. */
|
|
80
|
+
function textOf(element) {
|
|
81
|
+
return element === undefined ? '' : (element.textContent ?? '').replace(/\s+/g, '');
|
|
82
|
+
}
|
|
83
|
+
/** A forge certificate from base64 DER, or `undefined` when the bytes are not one. */
|
|
84
|
+
function certificateFromBase64(value) {
|
|
85
|
+
if (value === '') {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const der = forge.util.createBuffer(Buffer.from(value, 'base64').toString('binary'));
|
|
90
|
+
return forge.pki.certificateFromAsn1(forge.asn1.fromDer(der));
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The leaf of an `X509PKIPathv1` value: a DER `SEQUENCE OF Certificate`, leaf first (as
|
|
98
|
+
* `pkiPathBase64` writes it). `undefined` when the bytes are not such a sequence.
|
|
99
|
+
*/
|
|
100
|
+
function certificateFromPkiPath(value) {
|
|
101
|
+
try {
|
|
102
|
+
const der = forge.util.createBuffer(Buffer.from(value, 'base64').toString('binary'));
|
|
103
|
+
const sequence = forge.asn1.fromDer(der);
|
|
104
|
+
const first = Array.isArray(sequence.value) ? sequence.value[0] : undefined;
|
|
105
|
+
return first === undefined ? undefined : forge.pki.certificateFromAsn1(first);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Every certificate the truststore holds, parsed — and rendered to PEM and DER — once per call.
|
|
113
|
+
* Re-deriving these per signature is what made a large truststore quadratic.
|
|
114
|
+
*/
|
|
115
|
+
function truststoreCertificates(truststore) {
|
|
116
|
+
if (truststore === undefined) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
const certificates = [];
|
|
120
|
+
for (const alias of truststore.aliases) {
|
|
121
|
+
for (const pem of [alias.certPem, ...alias.chainPem]) {
|
|
122
|
+
try {
|
|
123
|
+
const cert = forge.pki.certificateFromPem(pem);
|
|
124
|
+
const normalized = forge.pki.certificateToPem(cert);
|
|
125
|
+
certificates.push({ cert, pem: normalized, der: certificateBase64(normalized) });
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// A truststore entry this build cannot parse simply trusts nothing.
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return certificates;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Parses an RFC 2253/4514 distinguished name into its attributes: split on unescaped `,` (and
|
|
136
|
+
* `+`, which joins a multi-valued RDN), then on the first unescaped `=`, unescaping `\x` and
|
|
137
|
+
* `\XX` hex pairs in the value.
|
|
138
|
+
*
|
|
139
|
+
* Needed because an `X509IssuerName` is only *semantically* equal to the DN this build renders:
|
|
140
|
+
* a peer is free to space, order and escape it differently, and comparing the rendered strings
|
|
141
|
+
* would reject a certificate we do hold.
|
|
142
|
+
*/
|
|
143
|
+
function parseRfc2253(dn) {
|
|
144
|
+
const parts = [];
|
|
145
|
+
let current = '';
|
|
146
|
+
for (let index = 0; index < dn.length; index += 1) {
|
|
147
|
+
const char = dn.charAt(index);
|
|
148
|
+
if (char === '\\') {
|
|
149
|
+
current += char + dn.charAt(index + 1);
|
|
150
|
+
index += 1;
|
|
151
|
+
}
|
|
152
|
+
else if (char === ',' || char === '+') {
|
|
153
|
+
parts.push(current);
|
|
154
|
+
current = '';
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
current += char;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
parts.push(current);
|
|
161
|
+
const attributes = [];
|
|
162
|
+
for (const part of parts) {
|
|
163
|
+
const separator = part.indexOf('=');
|
|
164
|
+
if (separator <= 0) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
attributes.push({
|
|
168
|
+
type: part.slice(0, separator).trim(),
|
|
169
|
+
value: unescapeRfc2253(part.slice(separator + 1).trim()),
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return attributes;
|
|
173
|
+
}
|
|
174
|
+
/** Undoes RFC 2253 escaping: `\c` is `c`, `\XX` is the byte `XX`. */
|
|
175
|
+
function unescapeRfc2253(value) {
|
|
176
|
+
let out = '';
|
|
177
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
178
|
+
const char = value.charAt(index);
|
|
179
|
+
if (char !== '\\') {
|
|
180
|
+
out += char;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const pair = value.slice(index + 1, index + 3);
|
|
184
|
+
if (/^[0-9a-fA-F]{2}$/.test(pair)) {
|
|
185
|
+
out += String.fromCharCode(Number.parseInt(pair, 16));
|
|
186
|
+
index += 2;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
out += value.charAt(index + 1);
|
|
190
|
+
index += 1;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
/** A DN's attributes as a sorted, comparable key: type case-insensitive, value verbatim. */
|
|
196
|
+
function dnKey(attributes) {
|
|
197
|
+
return attributes
|
|
198
|
+
.map((attribute) => `${attribute.type.toLowerCase()}=${attribute.value}`)
|
|
199
|
+
.sort()
|
|
200
|
+
.join(',');
|
|
201
|
+
}
|
|
202
|
+
/** Whether `issuerName` names the same DN as `attributes`, whatever rendering it arrived in. */
|
|
203
|
+
function sameDn(issuerName, attributes) {
|
|
204
|
+
const rendered = renderDnRfc2253(attributes);
|
|
205
|
+
// Fast path: the common case is a peer that renders the DN exactly as this build does.
|
|
206
|
+
return rendered === issuerName || dnKey(parseRfc2253(rendered)) === dnKey(parseRfc2253(issuerName));
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* The certificate a `ds:KeyInfo` names. Every X.509 token profile form is understood: the ones
|
|
210
|
+
* that *carry* the certificate (a `wsse:Reference` to a `BinarySecurityToken`, an `X509v3`
|
|
211
|
+
* `KeyIdentifier`, an inline `ds:X509Certificate`) yield it directly; the ones that merely
|
|
212
|
+
* *name* it (`IssuerSerial`, `SubjectKeyIdentifier`, `ThumbprintSHA1`) are looked up among
|
|
213
|
+
* `trusted`, which is why an untrusted signer using one of them cannot be resolved at all.
|
|
214
|
+
*/
|
|
215
|
+
function certificateFromKeyInfo(ids, keyInfo, trusted) {
|
|
216
|
+
if (keyInfo === undefined) {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
const reference = findElement(keyInfo, NS.WSSE, 'Reference');
|
|
220
|
+
if (reference !== undefined) {
|
|
221
|
+
const uri = reference.getAttribute('URI') ?? '';
|
|
222
|
+
const token = uri.startsWith('#') ? uniqueById(ids, uri.slice(1)) : undefined;
|
|
223
|
+
const value = textOf(token);
|
|
224
|
+
return certificateFromBase64(value) ?? certificateFromPkiPath(value);
|
|
225
|
+
}
|
|
226
|
+
const identifier = findElement(keyInfo, NS.WSSE, 'KeyIdentifier');
|
|
227
|
+
if (identifier !== undefined) {
|
|
228
|
+
const valueType = identifier.getAttribute('ValueType') ?? '';
|
|
229
|
+
const value = textOf(identifier);
|
|
230
|
+
if (valueType === WSS_TOKEN_TYPES.THUMBPRINT_SHA1) {
|
|
231
|
+
return lookup(trusted, (pem) => thumbprintSha1Base64(pem) === value);
|
|
232
|
+
}
|
|
233
|
+
if (valueType === WSS_TOKEN_TYPES.X509_SUBJECT_KEY_IDENTIFIER) {
|
|
234
|
+
return lookup(trusted, (pem) => subjectKeyIdentifierBase64(pem) === value);
|
|
235
|
+
}
|
|
236
|
+
return certificateFromBase64(value) ?? certificateFromPkiPath(value);
|
|
237
|
+
}
|
|
238
|
+
const issuerSerial = findElement(keyInfo, NS.DS, 'X509IssuerSerial');
|
|
239
|
+
if (issuerSerial !== undefined) {
|
|
240
|
+
const issuer = (childElement(issuerSerial, NS.DS, 'X509IssuerName')?.textContent ?? '').trim();
|
|
241
|
+
const serial = (childElement(issuerSerial, NS.DS, 'X509SerialNumber')?.textContent ?? '').trim();
|
|
242
|
+
return trusted.find((candidate) => sameDn(issuer, candidate.cert.issuer.attributes) &&
|
|
243
|
+
BigInt(`0x${candidate.cert.serialNumber}`).toString(10) === serial)?.cert;
|
|
244
|
+
}
|
|
245
|
+
const inline = findElement(keyInfo, NS.DS, 'X509Certificate');
|
|
246
|
+
return inline === undefined ? undefined : certificateFromBase64(textOf(inline));
|
|
247
|
+
}
|
|
248
|
+
/** The first trusted certificate whose PEM satisfies `matches`; a form it cannot compute never matches. */
|
|
249
|
+
function lookup(trusted, matches) {
|
|
250
|
+
return trusted.find((candidate) => {
|
|
251
|
+
try {
|
|
252
|
+
return matches(candidate.pem);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
})?.cert;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Whether `certificate` is trusted: byte-identical to a truststore certificate, or — with
|
|
261
|
+
* `verifyChain` — issued (transitively) by one of them, with every certificate in the path
|
|
262
|
+
* valid at `at`.
|
|
263
|
+
*/
|
|
264
|
+
function isTrusted(certificate, trusted, verifyChain, at) {
|
|
265
|
+
if (trusted.length === 0) {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
const der = certificateBase64(forge.pki.certificateToPem(certificate));
|
|
269
|
+
if (trusted.some((candidate) => candidate.der === der)) {
|
|
270
|
+
// Pinned, but an expired certificate is not a trusted one: the equality path has to judge
|
|
271
|
+
// validity against the injected clock exactly as the chain path does.
|
|
272
|
+
return (certificate.validity.notBefore.getTime() <= at.getTime() &&
|
|
273
|
+
at.getTime() <= certificate.validity.notAfter.getTime());
|
|
274
|
+
}
|
|
275
|
+
if (!verifyChain) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
const caStore = forge.pki.createCaStore(trusted.map((candidate) => candidate.cert));
|
|
280
|
+
// `validityCheckDate` is what makes the injected clock reach forge; without it the chain
|
|
281
|
+
// would be judged against the wall clock and a frozen-clock test could not exist.
|
|
282
|
+
return forge.pki.verifyCertificateChain(caStore, [certificate], { validityCheckDate: at });
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/** The `URI`s of a `ds:Signature`'s references, without their leading `#`. */
|
|
289
|
+
function referenceIds(signature) {
|
|
290
|
+
const signedInfo = childElement(signature, NS.DS, 'SignedInfo');
|
|
291
|
+
if (signedInfo === undefined) {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
return findAll(signedInfo, NS.DS, 'Reference')
|
|
295
|
+
.map((reference) => reference.getAttribute('URI') ?? '')
|
|
296
|
+
.filter((uri) => uri.startsWith('#'))
|
|
297
|
+
.map((uri) => uri.slice(1));
|
|
298
|
+
}
|
|
299
|
+
/** The envelope's `soap:Body`, in either SOAP version, or `undefined` for a non-SOAP document. */
|
|
300
|
+
function bodyElement(root) {
|
|
301
|
+
return findElement(root, NS.SOAP11_ENV, 'Body') ?? findElement(root, NS.SOAP12_ENV, 'Body');
|
|
302
|
+
}
|
|
303
|
+
/** Parses `wsu:Created`/`wsu:Expires`, returning `undefined` for anything not a date. */
|
|
304
|
+
function parseInstant(value) {
|
|
305
|
+
if (value === undefined || value.trim() === '') {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
const parsed = new Date(value.trim());
|
|
309
|
+
return Number.isNaN(parsed.getTime()) ? undefined : parsed;
|
|
310
|
+
}
|
|
311
|
+
/** Judges the `wsu:Timestamp` under `security`, or `undefined` when there is none. */
|
|
312
|
+
function readTimestamp(security, options) {
|
|
313
|
+
const timestamp = findElement(security, NS.WSU, 'Timestamp');
|
|
314
|
+
if (timestamp === undefined) {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
const createdText = childElement(timestamp, NS.WSU, 'Created')?.textContent ?? '';
|
|
318
|
+
const expiresElement = childElement(timestamp, NS.WSU, 'Expires');
|
|
319
|
+
const expiresText = expiresElement?.textContent ?? undefined;
|
|
320
|
+
const created = parseInstant(createdText);
|
|
321
|
+
const expires = parseInstant(expiresText);
|
|
322
|
+
const base = {
|
|
323
|
+
created: createdText.trim(),
|
|
324
|
+
...(expiresText !== undefined ? { expires: expiresText.trim() } : {}),
|
|
325
|
+
};
|
|
326
|
+
if (created === undefined) {
|
|
327
|
+
return { ...base, fresh: false, error: 'The timestamp has no readable wsu:Created.' };
|
|
328
|
+
}
|
|
329
|
+
const skewMs = options.skewSeconds * 1000;
|
|
330
|
+
const now = options.clock().getTime();
|
|
331
|
+
if (now + skewMs < created.getTime()) {
|
|
332
|
+
return { ...base, fresh: false, error: 'The message was created in the future.' };
|
|
333
|
+
}
|
|
334
|
+
if (expires !== undefined) {
|
|
335
|
+
return now - skewMs > expires.getTime()
|
|
336
|
+
? { ...base, fresh: false, error: 'The message expired.' }
|
|
337
|
+
: { ...base, fresh: true };
|
|
338
|
+
}
|
|
339
|
+
// No `Expires`: the skew window is all there is to judge against, so a `Created` older than
|
|
340
|
+
// it is stale rather than merely unbounded.
|
|
341
|
+
return now - skewMs > created.getTime()
|
|
342
|
+
? { ...base, fresh: false, error: 'The message is older than the tolerated clock skew.' }
|
|
343
|
+
: { ...base, fresh: true };
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Verifies every `ds:Signature` in `xml`'s `wsse:Security` headers and reads its
|
|
347
|
+
* `wsu:Timestamp`.
|
|
348
|
+
*
|
|
349
|
+
* Never throws: an unparsable, unsigned or non-SOAP message simply produces no signatures and
|
|
350
|
+
* no timestamp, which is what "this response had no WS-Security" has to look like.
|
|
351
|
+
*
|
|
352
|
+
* @param xml the (already decrypted) response envelope
|
|
353
|
+
* @param options the truststore, the clock, the tolerated skew and whether to follow chains
|
|
354
|
+
* @returns one result per signature, plus the timestamp when the message carries one
|
|
355
|
+
*/
|
|
356
|
+
export function verifyIncoming(xml, options) {
|
|
357
|
+
let doc;
|
|
358
|
+
let root;
|
|
359
|
+
try {
|
|
360
|
+
doc = parseXml(xml, { location: 'envelope' });
|
|
361
|
+
root = doc.documentElement ?? undefined;
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
return { signatures: [] };
|
|
365
|
+
}
|
|
366
|
+
if (doc === undefined || root === undefined) {
|
|
367
|
+
return { signatures: [] };
|
|
368
|
+
}
|
|
369
|
+
const securities = findAll(root, NS.WSSE, 'Security');
|
|
370
|
+
const securitySignatures = new Set(securities.flatMap((security) => findAll(security, NS.DS, 'Signature')));
|
|
371
|
+
// Document order, and every `ds:Signature` — including one planted outside a `wsse:Security`
|
|
372
|
+
// header, which is reported as a failure rather than quietly ignored, because a wrapping
|
|
373
|
+
// payload the user cannot see is worse than one that reads as broken.
|
|
374
|
+
const signatures = findAll(root, NS.DS, 'Signature');
|
|
375
|
+
const trusted = truststoreCertificates(options.truststore);
|
|
376
|
+
const ids = idIndex(root);
|
|
377
|
+
const body = bodyElement(root);
|
|
378
|
+
const at = options.clock();
|
|
379
|
+
// A `ds:Signature` outside every `wsse:Security` header is never itself validated (see the
|
|
380
|
+
// early return below) — it is noise a wrapping attack planted to be picked up as content, not
|
|
381
|
+
// a signature this build ever trusts. Removing that noise once, up front, is not the isolation
|
|
382
|
+
// this code once did per signature (which stripped *every other* signature, including a
|
|
383
|
+
// legitimate sibling in the same `wsse:Security` header, corrupting the digest of any
|
|
384
|
+
// reference — such as an enveloped-signature transform over the header itself — that
|
|
385
|
+
// legitimately covered that sibling). A header signature is always verified against the
|
|
386
|
+
// document exactly as its Security header holds it; only content that could never have been
|
|
387
|
+
// part of a real signature's input is taken out first.
|
|
388
|
+
const headerSignatures = signatures.filter((signature) => securitySignatures.has(signature));
|
|
389
|
+
for (const signature of signatures) {
|
|
390
|
+
if (!securitySignatures.has(signature)) {
|
|
391
|
+
signature.parentNode?.removeChild(signature);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const sanitizedXml = serializeXml(doc);
|
|
395
|
+
const results = signatures.map((signature) => {
|
|
396
|
+
const empty = { references: [], referenceNames: [], coversBody: false, trusted: false };
|
|
397
|
+
if (!securitySignatures.has(signature)) {
|
|
398
|
+
return { ...empty, ok: false, error: 'A ds:Signature outside the wsse:Security header is not accepted.' };
|
|
399
|
+
}
|
|
400
|
+
const referenced = referenceIds(signature);
|
|
401
|
+
const duplicated = referenced.filter((id) => (ids.get(id)?.length ?? 0) > 1);
|
|
402
|
+
if (duplicated.length > 0) {
|
|
403
|
+
return {
|
|
404
|
+
...empty,
|
|
405
|
+
ok: false,
|
|
406
|
+
references: referenced,
|
|
407
|
+
error: `duplicate-id: more than one element carries the referenced id "${duplicated[0] ?? ''}".`,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const certificate = certificateFromKeyInfo(ids, childElement(signature, NS.DS, 'KeyInfo'), trusted);
|
|
411
|
+
if (certificate === undefined) {
|
|
412
|
+
return {
|
|
413
|
+
...empty,
|
|
414
|
+
ok: false,
|
|
415
|
+
error: 'The signing certificate could not be resolved from the message or the truststore.',
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
const certPem = forge.pki.certificateToPem(certificate);
|
|
419
|
+
// Verified by the signature's position among `wsse:Security` header signatures — never by
|
|
420
|
+
// isolating it from its own header siblings, which would change the bytes a signature whose
|
|
421
|
+
// own references cover the wsse:Security header (an enveloped-signature transform over a
|
|
422
|
+
// header that holds a second signature) was actually computed over.
|
|
423
|
+
const result = verifySignature(sanitizedXml, {
|
|
424
|
+
certPem,
|
|
425
|
+
signature: { index: headerSignatures.indexOf(signature) },
|
|
426
|
+
});
|
|
427
|
+
const covered = result.references.map((id) => uniqueById(ids, id));
|
|
428
|
+
return {
|
|
429
|
+
ok: result.ok,
|
|
430
|
+
references: result.references,
|
|
431
|
+
referenceNames: covered.map((element, index) => element?.localName ?? result.references[index] ?? ''),
|
|
432
|
+
coversBody: result.ok && body !== undefined && covered.includes(body),
|
|
433
|
+
signerSubject: renderDn(certificate.subject.attributes),
|
|
434
|
+
trusted: isTrusted(certificate, trusted, options.verifyChain, at),
|
|
435
|
+
...(result.error !== undefined ? { error: result.error } : {}),
|
|
436
|
+
};
|
|
437
|
+
});
|
|
438
|
+
const timestamp = securities.map((security) => readTimestamp(security, options)).find((found) => found !== undefined);
|
|
439
|
+
return { signatures: results, ...(timestamp !== undefined ? { timestamp } : {}) };
|
|
440
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `<ds:KeyInfo>` content an outgoing signature carries: a `wsse:SecurityTokenReference`
|
|
3
|
+
* (or a bare `ds:X509Data`) pointing at the signing certificate in one of the five forms the
|
|
4
|
+
* X.509 token profile defines.
|
|
5
|
+
*
|
|
6
|
+
* These are produced as XML *strings* rather than DOM nodes because `xml-crypto` builds the
|
|
7
|
+
* whole `<ds:Signature>` element by string concatenation and asks for the KeyInfo contents the
|
|
8
|
+
* same way. Every element therefore declares the prefixes it uses on itself.
|
|
9
|
+
*/
|
|
10
|
+
import type { WssKeyIdentifierType } from './model.js';
|
|
11
|
+
/** `ValueType`/`EncodingType` URIs from the WS-Security X.509 token profile. */
|
|
12
|
+
export declare const WSS_TOKEN_TYPES: {
|
|
13
|
+
/** A single DER-encoded certificate. */
|
|
14
|
+
readonly X509V3: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
|
|
15
|
+
/** An ordered DER PKIPath of certificates. */
|
|
16
|
+
readonly X509_PKI_PATH_V1: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1";
|
|
17
|
+
/** The certificate's subject key identifier extension value. */
|
|
18
|
+
readonly X509_SUBJECT_KEY_IDENTIFIER: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier";
|
|
19
|
+
/** SHA-1 of the DER encoding of the certificate. */
|
|
20
|
+
readonly THUMBPRINT_SHA1: "http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1";
|
|
21
|
+
/** Base64 content encoding. */
|
|
22
|
+
readonly BASE64_BINARY: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
|
|
23
|
+
};
|
|
24
|
+
/** What every key-identifier builder needs about the signing certificate. */
|
|
25
|
+
export interface KeyIdentifierInput {
|
|
26
|
+
/** The signing (leaf) certificate, PEM encoded. */
|
|
27
|
+
readonly certPem: string;
|
|
28
|
+
/** The issuing chain, nearest first; only used for `X509PKIPathv1`. */
|
|
29
|
+
readonly chainPem: readonly string[];
|
|
30
|
+
/** Emit only the leaf rather than the whole path. */
|
|
31
|
+
readonly useSingleCertificate: boolean;
|
|
32
|
+
/** The `wsu:Id` a `BinarySecurityToken` gets (and the `wsse:Reference` points at). */
|
|
33
|
+
readonly tokenId: string;
|
|
34
|
+
}
|
|
35
|
+
/** The KeyInfo content plus, for `BinarySecurityToken`, the token that must precede the signature. */
|
|
36
|
+
export interface KeyIdentifier {
|
|
37
|
+
/** The XML that goes inside `<ds:KeyInfo>`. */
|
|
38
|
+
readonly keyInfoXml: string;
|
|
39
|
+
/** The `<wsse:BinarySecurityToken>` to insert into `wsse:Security`, when this form needs one. */
|
|
40
|
+
readonly binarySecurityTokenXml?: string;
|
|
41
|
+
}
|
|
42
|
+
/** The DER bytes of a PEM certificate. */
|
|
43
|
+
export declare function certificateDer(certPem: string): Buffer;
|
|
44
|
+
/** Base64 of the DER encoding of `certPem`, unwrapped (one line). */
|
|
45
|
+
export declare function certificateBase64(certPem: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Base64 of the DER `PKIPath` (an ASN.1 SEQUENCE OF Certificate) holding the leaf and its chain.
|
|
48
|
+
*
|
|
49
|
+
* @param certPems the certificates, leaf first
|
|
50
|
+
* @returns the base64 the `X509PKIPathv1` value type expects
|
|
51
|
+
*/
|
|
52
|
+
export declare function pkiPathBase64(certPems: readonly string[]): string;
|
|
53
|
+
/** SHA-1 of the certificate's DER encoding, base64 encoded (the `ThumbprintSHA1` value). */
|
|
54
|
+
export declare function thumbprintSha1Base64(certPem: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* The certificate's subject key identifier extension value, base64 encoded.
|
|
57
|
+
*
|
|
58
|
+
* @param certPem the certificate to read
|
|
59
|
+
* @returns the base64 `X509SubjectKeyIdentifier` value
|
|
60
|
+
* @throws WssError `wss-ski-missing` when the certificate carries no such extension
|
|
61
|
+
*/
|
|
62
|
+
export declare function subjectKeyIdentifierBase64(certPem: string): string;
|
|
63
|
+
/** The certificate's issuer as an RFC 2253 distinguished name (most specific attribute first). */
|
|
64
|
+
export declare function issuerDnRfc2253(certPem: string): string;
|
|
65
|
+
/** The certificate's serial number in decimal, as `ds:X509SerialNumber` requires. */
|
|
66
|
+
export declare function serialNumberDecimal(certPem: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Builds the `ds:KeyInfo` content (and any `wsse:BinarySecurityToken`) for one key identifier
|
|
69
|
+
* form.
|
|
70
|
+
*
|
|
71
|
+
* @param type which of the five X.509 token profile forms to emit
|
|
72
|
+
* @param input the signing certificate, its chain and the token id to use
|
|
73
|
+
* @returns the KeyInfo XML, plus the binary security token when the form needs one
|
|
74
|
+
* @throws WssError `wss-ski-missing` for `SubjectKeyIdentifier` on a certificate without one
|
|
75
|
+
*/
|
|
76
|
+
export declare function buildKeyIdentifier(type: WssKeyIdentifierType, input: KeyIdentifierInput): KeyIdentifier;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `<ds:KeyInfo>` content an outgoing signature carries: a `wsse:SecurityTokenReference`
|
|
3
|
+
* (or a bare `ds:X509Data`) pointing at the signing certificate in one of the five forms the
|
|
4
|
+
* X.509 token profile defines.
|
|
5
|
+
*
|
|
6
|
+
* These are produced as XML *strings* rather than DOM nodes because `xml-crypto` builds the
|
|
7
|
+
* whole `<ds:Signature>` element by string concatenation and asks for the KeyInfo contents the
|
|
8
|
+
* same way. Every element therefore declares the prefixes it uses on itself.
|
|
9
|
+
*/
|
|
10
|
+
import { createHash } from 'node:crypto';
|
|
11
|
+
import forge from 'node-forge';
|
|
12
|
+
import { WssError } from '../errors.js';
|
|
13
|
+
import { NS } from '../xml/namespaces.js';
|
|
14
|
+
import { renderDnRfc2253 } from './keystore/certificate.js';
|
|
15
|
+
/** `ValueType`/`EncodingType` URIs from the WS-Security X.509 token profile. */
|
|
16
|
+
export const WSS_TOKEN_TYPES = {
|
|
17
|
+
/** A single DER-encoded certificate. */
|
|
18
|
+
X509V3: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3',
|
|
19
|
+
/** An ordered DER PKIPath of certificates. */
|
|
20
|
+
X509_PKI_PATH_V1: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1',
|
|
21
|
+
/** The certificate's subject key identifier extension value. */
|
|
22
|
+
X509_SUBJECT_KEY_IDENTIFIER: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier',
|
|
23
|
+
/** SHA-1 of the DER encoding of the certificate. */
|
|
24
|
+
THUMBPRINT_SHA1: 'http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1',
|
|
25
|
+
/** Base64 content encoding. */
|
|
26
|
+
BASE64_BINARY: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary',
|
|
27
|
+
};
|
|
28
|
+
/** Escapes the five XML significant characters in attribute/text content. */
|
|
29
|
+
function escapeXml(value) {
|
|
30
|
+
return value
|
|
31
|
+
.replace(/&/g, '&')
|
|
32
|
+
.replace(/</g, '<')
|
|
33
|
+
.replace(/>/g, '>')
|
|
34
|
+
.replace(/"/g, '"')
|
|
35
|
+
.replace(/'/g, ''');
|
|
36
|
+
}
|
|
37
|
+
/** The DER bytes of a PEM certificate. */
|
|
38
|
+
export function certificateDer(certPem) {
|
|
39
|
+
const der = forge.asn1.toDer(forge.pki.certificateToAsn1(forge.pki.certificateFromPem(certPem))).getBytes();
|
|
40
|
+
return Buffer.from(der, 'binary');
|
|
41
|
+
}
|
|
42
|
+
/** Base64 of the DER encoding of `certPem`, unwrapped (one line). */
|
|
43
|
+
export function certificateBase64(certPem) {
|
|
44
|
+
return certificateDer(certPem).toString('base64');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Base64 of the DER `PKIPath` (an ASN.1 SEQUENCE OF Certificate) holding the leaf and its chain.
|
|
48
|
+
*
|
|
49
|
+
* @param certPems the certificates, leaf first
|
|
50
|
+
* @returns the base64 the `X509PKIPathv1` value type expects
|
|
51
|
+
*/
|
|
52
|
+
export function pkiPathBase64(certPems) {
|
|
53
|
+
const certificates = certPems.map((pem) => forge.pki.certificateToAsn1(forge.pki.certificateFromPem(pem)));
|
|
54
|
+
const sequence = forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.SEQUENCE, true, certificates);
|
|
55
|
+
return Buffer.from(forge.asn1.toDer(sequence).getBytes(), 'binary').toString('base64');
|
|
56
|
+
}
|
|
57
|
+
/** SHA-1 of the certificate's DER encoding, base64 encoded (the `ThumbprintSHA1` value). */
|
|
58
|
+
export function thumbprintSha1Base64(certPem) {
|
|
59
|
+
return createHash('sha1').update(certificateDer(certPem)).digest('base64');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The certificate's subject key identifier extension value, base64 encoded.
|
|
63
|
+
*
|
|
64
|
+
* @param certPem the certificate to read
|
|
65
|
+
* @returns the base64 `X509SubjectKeyIdentifier` value
|
|
66
|
+
* @throws WssError `wss-ski-missing` when the certificate carries no such extension
|
|
67
|
+
*/
|
|
68
|
+
export function subjectKeyIdentifierBase64(certPem) {
|
|
69
|
+
const cert = forge.pki.certificateFromPem(certPem);
|
|
70
|
+
const extension = cert.extensions.find((candidate) => candidate.name === 'subjectKeyIdentifier' || candidate.id === '2.5.29.14');
|
|
71
|
+
const hex = extension?.subjectKeyIdentifier;
|
|
72
|
+
if (typeof hex !== 'string' || hex.length === 0) {
|
|
73
|
+
throw new WssError('wss-ski-missing', 'The signing certificate has no Subject Key Identifier extension; choose another key identifier type.');
|
|
74
|
+
}
|
|
75
|
+
return Buffer.from(hex, 'hex').toString('base64');
|
|
76
|
+
}
|
|
77
|
+
/** The certificate's issuer as an RFC 2253 distinguished name (most specific attribute first). */
|
|
78
|
+
export function issuerDnRfc2253(certPem) {
|
|
79
|
+
const cert = forge.pki.certificateFromPem(certPem);
|
|
80
|
+
return renderDnRfc2253(cert.issuer.attributes);
|
|
81
|
+
}
|
|
82
|
+
/** The certificate's serial number in decimal, as `ds:X509SerialNumber` requires. */
|
|
83
|
+
export function serialNumberDecimal(certPem) {
|
|
84
|
+
const cert = forge.pki.certificateFromPem(certPem);
|
|
85
|
+
return BigInt(`0x${cert.serialNumber}`).toString(10);
|
|
86
|
+
}
|
|
87
|
+
/** Opens a `wsse:SecurityTokenReference`, declaring both WS-Security prefixes on itself. */
|
|
88
|
+
function securityTokenReference(inner) {
|
|
89
|
+
return `<wsse:SecurityTokenReference xmlns:wsse="${NS.WSSE}" xmlns:wsu="${NS.WSU}">${inner}</wsse:SecurityTokenReference>`;
|
|
90
|
+
}
|
|
91
|
+
/** A `<wsse:KeyIdentifier>` carrying base64 content of the given value type. */
|
|
92
|
+
function keyIdentifierElement(valueType, value) {
|
|
93
|
+
return (`<wsse:KeyIdentifier ValueType="${valueType}" EncodingType="${WSS_TOKEN_TYPES.BASE64_BINARY}">` +
|
|
94
|
+
`${value}</wsse:KeyIdentifier>`);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Builds the `ds:KeyInfo` content (and any `wsse:BinarySecurityToken`) for one key identifier
|
|
98
|
+
* form.
|
|
99
|
+
*
|
|
100
|
+
* @param type which of the five X.509 token profile forms to emit
|
|
101
|
+
* @param input the signing certificate, its chain and the token id to use
|
|
102
|
+
* @returns the KeyInfo XML, plus the binary security token when the form needs one
|
|
103
|
+
* @throws WssError `wss-ski-missing` for `SubjectKeyIdentifier` on a certificate without one
|
|
104
|
+
*/
|
|
105
|
+
export function buildKeyIdentifier(type, input) {
|
|
106
|
+
switch (type) {
|
|
107
|
+
case 'BinarySecurityToken': {
|
|
108
|
+
const valueType = input.useSingleCertificate ? WSS_TOKEN_TYPES.X509V3 : WSS_TOKEN_TYPES.X509_PKI_PATH_V1;
|
|
109
|
+
const value = input.useSingleCertificate
|
|
110
|
+
? certificateBase64(input.certPem)
|
|
111
|
+
: pkiPathBase64([input.certPem, ...input.chainPem]);
|
|
112
|
+
return {
|
|
113
|
+
keyInfoXml: securityTokenReference(`<wsse:Reference URI="#${input.tokenId}" ValueType="${valueType}"/>`),
|
|
114
|
+
binarySecurityTokenXml: `<wsse:BinarySecurityToken xmlns:wsse="${NS.WSSE}" xmlns:wsu="${NS.WSU}" ` +
|
|
115
|
+
`wsu:Id="${input.tokenId}" EncodingType="${WSS_TOKEN_TYPES.BASE64_BINARY}" ` +
|
|
116
|
+
`ValueType="${valueType}">${value}</wsse:BinarySecurityToken>`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
case 'IssuerSerial':
|
|
120
|
+
return {
|
|
121
|
+
keyInfoXml: `<ds:X509Data xmlns:ds="${NS.DS}"><ds:X509IssuerSerial>` +
|
|
122
|
+
`<ds:X509IssuerName>${escapeXml(issuerDnRfc2253(input.certPem))}</ds:X509IssuerName>` +
|
|
123
|
+
`<ds:X509SerialNumber>${serialNumberDecimal(input.certPem)}</ds:X509SerialNumber>` +
|
|
124
|
+
`</ds:X509IssuerSerial></ds:X509Data>`,
|
|
125
|
+
};
|
|
126
|
+
case 'SubjectKeyIdentifier':
|
|
127
|
+
return {
|
|
128
|
+
keyInfoXml: securityTokenReference(keyIdentifierElement(WSS_TOKEN_TYPES.X509_SUBJECT_KEY_IDENTIFIER, subjectKeyIdentifierBase64(input.certPem))),
|
|
129
|
+
};
|
|
130
|
+
case 'X509KeyIdentifier':
|
|
131
|
+
return {
|
|
132
|
+
keyInfoXml: securityTokenReference(keyIdentifierElement(WSS_TOKEN_TYPES.X509V3, certificateBase64(input.certPem))),
|
|
133
|
+
};
|
|
134
|
+
case 'Thumbprint':
|
|
135
|
+
return {
|
|
136
|
+
keyInfoXml: securityTokenReference(keyIdentifierElement(WSS_TOKEN_TYPES.THUMBPRINT_SHA1, thumbprintSha1Base64(input.certPem))),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|