typepki-asn1gen 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  typepki-asn1gen: ASN.1 data generator for TypePKI library
2
2
  =========================================================
3
3
 
4
- [TOP](https://kjur.github.io/typepki-asn1gen/) | [github](https://github.com/kjur/typepki-asn1gen) | [npm](https://www.npmjs.com/package/typepki-asn1gen) | [TypePKI](https://kjur.github.com/typepki/)
4
+ [TOP](https://kjur.github.io/typepki-asn1gen/) | [github](https://github.com/kjur/typepki-asn1gen) | [npm](https://www.npmjs.com/package/typepki-asn1gen) | [TypePKI](https://kjur.github.io/typepki/)
5
5
 
6
6
  The 'TypePKI' library is an opensource free TypeScript PKI library which is the successor of the long lived [jsrsasign](https://kjur.github.io/jsrsasign) library.
7
7
 
@@ -19,6 +19,17 @@ export interface ASN1Data {
19
19
  * ]}) -> "3006020101020102"
20
20
  */
21
21
  export declare function getASN1(p: ASN1Data): string;
22
+ /**
23
+ * get a hexadecimal string of ASN.1 tag by a tag name
24
+ * @param tagName - name of ASN.1 tag
25
+ * @return hexadecimal string of ASN.1 tag
26
+ * @example
27
+ * tagtohex("bool") -> "01"
28
+ * tagtohex("utf8str") -> "0c"
29
+ * tagtohex("a4") -> context specific constructed tag 4
30
+ * tagtohex("80") -> context specific tag 0
31
+ */
32
+ export declare function tagtohex(tagName: string): string;
22
33
  /**
23
34
  * convert hexadecimal positive integer to ASN.1 integer value
24
35
  * @param h - hexadecimal string of positive integer
@@ -43,6 +54,7 @@ export declare function getLength(n: number): string;
43
54
  * zero padding for hexadecimal string
44
55
  * @param s - odd or even length hexadecimal string
45
56
  * @return even length zero padded hexadecimal string
57
+ * @deprecated use hexpad in typepki-strconv
46
58
  * @example
47
59
  * hexpad("1") -> "01"
48
60
  * hexpad("ab3c") -> "ab3c"
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/index.mts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,GAAG,CAAC;CACR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAQ3C;AAiBD;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIxC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAU3C;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAExC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/index.mts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,GAAG,CAAC;CACR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAmB3C;AAaD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA4BhD;AAiBD;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIxC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAU3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAExC"}
@@ -1 +1 @@
1
- function r(t){return!(t.length%2===1||t.match(/^[0-9a-f]+$/)==null)}function u(t){switch(t.t){case"int":return i(t.v);case"seq":return l(t.v)}return""}function i(t){return typeof t=="string"&&r(t)?`02${s(t.length/2)}${t}`:""}function l(t){let e="";for(let n=0;n<t.length;n++)e+=u(t[n]);return`30${s(e.length/2)}${e}`}function h(t){return t=t.replace(/^(00){1,}/,""),t.match(/^[8-9a-f]/)?"00"+t:t}function s(t){let e;return t<128?(e=o(t.toString(16)),e):(e=o(t.toString(16)),(128+e.length/2).toString(16)+e)}function o(t){return t.length%2===1?`0${t}`:t}export{u as getASN1,s as getLength,o as hexpad,h as pospad};
1
+ function c(t){if(t.t=="asn"&&"tlv"in t.v)return t.v.tlv;if(t.t=="seq"||t.t=="set"||t.t.match(/^a\d$/)){let n="";for(let s=0;s<t.v.length;s++)n+=c(t.v[s]);let l=i(n.length/2);return`${u(t.t)}${l}${n}`}let e=u(t.t),r=f(t.v),o=i(r.length/2);return`${e}${o}${r}`}function f(t){if(typeof t=="string"){if(t.match(/^[0-9a-f]+$/))return t;throw new Error("string but not hex")}else if(typeof t=="object"){if("hex"in t&&typeof t.hex=="string")return t.hex;throw new Error(`unsupported value object: ${JSON.stringify(t)}`)}throw new Error("unsupported value")}function u(t){switch(t){case"bool":return"01";case"int":return"02";case"bitstr":return"03";case"octstr":return"04";case"null":return"05";case"oid":return"06";case"enum":return"0a";case"utf8str":return"0c";case"numstr":return"12";case"prnstr":return"13";case"telstr":return"14";case"vidstr":return"15";case"ia5str":return"16";case"utctime":return"17";case"gentime":return"18";case"grastr":return"19";case"visstr":return"1a";case"genstr":return"1b";case"unistr":return"1c";case"chrstr":return"1d";case"bmpstr":return"1e";case"seq":return"30";case"set":return"31"}if(t.match(/^[8a]\d$/))return t;throw new Error(`unsupported tagName: ${t}`)}function m(t){return t=t.replace(/^(00){1,}/,""),t.match(/^[8-9a-f]/)?"00"+t:t}function i(t){let e;return t<128?(e=a(t.toString(16)),e):(e=a(t.toString(16)),(128+e.length/2).toString(16)+e)}function a(t){return t.length%2===1?`0${t}`:t}export{c as getASN1,i as getLength,a as hexpad,m as pospad,u as tagtohex};
@@ -1 +1 @@
1
- "use strict";var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var l=(t,e)=>()=>(t&&(e=t(t=0)),e);var b=(t,e)=>{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},d=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of $(e))!m.call(t,r)&&r!==n&&s(t,r,{get:()=>e[r],enumerable:!(o=p(e,r))||o.enumerable});return t};var x=t=>d(s({},"__esModule",{value:!0}),t);function a(t){return!(t.length%2===1||t.match(/^[0-9a-f]+$/)==null)}var f=l(()=>{});var h={};b(h,{getASN1:()=>c,getLength:()=>i,hexpad:()=>u,pospad:()=>I});function c(t){switch(t.t){case"int":return w(t.v);case"seq":return S(t.v)}return""}function w(t){return typeof t=="string"&&a(t)?`02${i(t.length/2)}${t}`:""}function S(t){let e="";for(let n=0;n<t.length;n++)e+=c(t[n]);return`30${i(e.length/2)}${e}`}function I(t){return t=t.replace(/^(00){1,}/,""),t.match(/^[8-9a-f]/)?"00"+t:t}function i(t){let e;return t<128?(e=u(t.toString(16)),e):(e=u(t.toString(16)),(128+e.length/2).toString(16)+e)}function u(t){return t.length%2===1?`0${t}`:t}var g=l(()=>{"use strict";f()});module.exports=(g(),x(h));
1
+ "use strict";var u=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var c=(t,e)=>()=>(t&&(e=t(t=0)),e);var x=(t,e)=>{for(var n in e)u(t,n,{get:e[n],enumerable:!0})},w=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of b(e))!d.call(t,r)&&r!==n&&u(t,r,{get:()=>e[r],enumerable:!(s=m(e,r))||s.enumerable});return t};var S=t=>w(u({},"__esModule",{value:!0}),t);var f=c(()=>{});var g={};x(g,{getASN1:()=>h,getLength:()=>a,hexpad:()=>l,pospad:()=>y,tagtohex:()=>i});function h(t){if(t.t=="asn"&&"tlv"in t.v)return t.v.tlv;if(t.t=="seq"||t.t=="set"||t.t.match(/^a\d$/)){let r="";for(let o=0;o<t.v.length;o++)r+=h(t.v[o]);let $=a(r.length/2);return`${i(t.t)}${$}${r}`}let e=i(t.t),n=I(t.v),s=a(n.length/2);return`${e}${s}${n}`}function I(t){if(typeof t=="string"){if(t.match(/^[0-9a-f]+$/))return t;throw new Error("string but not hex")}else if(typeof t=="object"){if("hex"in t&&typeof t.hex=="string")return t.hex;throw new Error(`unsupported value object: ${JSON.stringify(t)}`)}throw new Error("unsupported value")}function i(t){switch(t){case"bool":return"01";case"int":return"02";case"bitstr":return"03";case"octstr":return"04";case"null":return"05";case"oid":return"06";case"enum":return"0a";case"utf8str":return"0c";case"numstr":return"12";case"prnstr":return"13";case"telstr":return"14";case"vidstr":return"15";case"ia5str":return"16";case"utctime":return"17";case"gentime":return"18";case"grastr":return"19";case"visstr":return"1a";case"genstr":return"1b";case"unistr":return"1c";case"chrstr":return"1d";case"bmpstr":return"1e";case"seq":return"30";case"set":return"31"}if(t.match(/^[8a]\d$/))return t;throw new Error(`unsupported tagName: ${t}`)}function y(t){return t=t.replace(/^(00){1,}/,""),t.match(/^[8-9a-f]/)?"00"+t:t}function a(t){let e;return t<128?(e=l(t.toString(16)),e):(e=l(t.toString(16)),(128+e.length/2).toString(16)+e)}function l(t){return t.length%2===1?`0${t}`:t}var p=c(()=>{"use strict";f()});module.exports=(p(),S(g));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typepki-asn1gen",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "author": "Kenji Urushima <kenji.urushima@gmail.com>",
5
5
  "description": "ASN.1 data generator for TypePKI library (beta)",
6
6
  "homepage": "https://kjur.github.io/typepki-asn1gen",
@@ -29,7 +29,7 @@
29
29
  "precommit": "run-z check:type fix test build",
30
30
  "prepublish": "attw --pack .",
31
31
  "run-z": "run-z",
32
- "doc": "typedoc --includeVersion --cleanOutputDir false --tsconfig ./tsconfig.typedoc.json --options ./typedoc.json src/index.mts"
32
+ "doc": "typedoc --includeVersion --cleanOutputDir false --tsconfig ./tsconfig.typedoc.json --options ./typedoc.json src/index.mts --skipErrorChecking"
33
33
  },
34
34
  "files": [
35
35
  "src",
@@ -56,13 +56,14 @@
56
56
  "@changesets/cli": "^2.27.1",
57
57
  "@types/bun": "^1.1.1",
58
58
  "bun-types": "^1.1.4",
59
- "esbuild": "^0.20.0",
59
+ "esbuild": "^0.27.2",
60
60
  "jest": "^29.7.0",
61
61
  "run-z": "^2.0.0",
62
62
  "typedoc": "^0.25.13",
63
63
  "typescript": "^5.4.5"
64
64
  },
65
65
  "dependencies": {
66
- "typepki-strconv": "^0.3.0"
66
+ "typepki-asn1gen": "file:typepki-asn1gen-0.2.0.tgz",
67
+ "typepki-strconv": "^0.5.0"
67
68
  }
68
69
  }
package/src/index.mts CHANGED
@@ -22,15 +22,77 @@ export interface ASN1Data {
22
22
  * ]}) -> "3006020101020102"
23
23
  */
24
24
  export function getASN1(p: ASN1Data): string {
25
- switch (p.t) {
26
- case "int":
27
- return generateASN1_int(p.v);
28
- case "seq":
29
- return generateASN1_seq(p.v);
25
+ if (p.t == "asn" && "tlv" in p.v) return p.v.tlv;
26
+
27
+ if (p.t == "seq" || p.t == "set" || p.t.match(/^a\d$/)) {
28
+ let hV = "";
29
+ for (let i = 0; i < p.v.length; i++) {
30
+ hV += getASN1(p.v[i]);
31
+ }
32
+ const hL = getLength(hV.length / 2);
33
+ const hT = tagtohex(p.t);
34
+ return `${hT}${hL}${hV}`;
30
35
  }
36
+
37
+ const hT: string = tagtohex(p.t);
38
+ const hV: string = _getValueHex(p.v);
39
+ const hL: string = getLength(hV.length / 2);
40
+ return `${hT}${hL}${hV}`;
41
+
31
42
  return "";
32
43
  }
33
44
 
45
+ function _getValueHex(value: string | object): string {
46
+ if (typeof value === "string") {
47
+ if (value.match(/^[0-9a-f]+$/)) return value;
48
+ throw new Error("string but not hex");
49
+ } else if (typeof value === "object") {
50
+ if ("hex" in value && typeof value.hex == "string") return value.hex;
51
+ throw new Error(`unsupported value object: ${JSON.stringify(value)}`);
52
+ }
53
+ throw new Error("unsupported value");
54
+ }
55
+
56
+ /**
57
+ * get a hexadecimal string of ASN.1 tag by a tag name
58
+ * @param tagName - name of ASN.1 tag
59
+ * @return hexadecimal string of ASN.1 tag
60
+ * @example
61
+ * tagtohex("bool") -> "01"
62
+ * tagtohex("utf8str") -> "0c"
63
+ * tagtohex("a4") -> context specific constructed tag 4
64
+ * tagtohex("80") -> context specific tag 0
65
+ */
66
+ export function tagtohex(tagName: string): string {
67
+ switch (tagName) {
68
+ case "bool": return "01";
69
+ case "int": return "02";
70
+ case "bitstr": return "03";
71
+ case "octstr": return "04";
72
+ case "null": return "05";
73
+ case "oid": return "06";
74
+ case "enum": return "0a";
75
+ case "utf8str": return "0c";
76
+ case "numstr": return "12";
77
+ case "prnstr": return "13";
78
+ case "telstr": return "14";
79
+ case "vidstr": return "15";
80
+ case "ia5str": return "16";
81
+ case "utctime": return "17";
82
+ case "gentime": return "18";
83
+ case "grastr": return "19";
84
+ case "visstr": return "1a";
85
+ case "genstr": return "1b";
86
+ case "unistr": return "1c";
87
+ case "chrstr": return "1d";
88
+ case "bmpstr": return "1e";
89
+ case "seq": return "30";
90
+ case "set": return "31";
91
+ }
92
+ if (tagName.match(/^[8a]\d$/)) return tagName;
93
+ throw new Error(`unsupported tagName: ${tagName}`);
94
+ }
95
+
34
96
  function generateASN1_int(v: string | object): string {
35
97
  if (typeof v == "string" && ishex(v)) {
36
98
  return `02${getLength(v.length / 2)}${v}`;
@@ -86,6 +148,7 @@ export function getLength(n: number): string {
86
148
  * zero padding for hexadecimal string
87
149
  * @param s - odd or even length hexadecimal string
88
150
  * @return even length zero padded hexadecimal string
151
+ * @deprecated use hexpad in typepki-strconv
89
152
  * @example
90
153
  * hexpad("1") -> "01"
91
154
  * hexpad("ab3c") -> "ab3c"
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, test } from "bun:test";
2
- import { pospad, getLength, getASN1 } from "./index.mts";
2
+ import { pospad, getLength, getASN1, tagtohex } from "./index.mts";
3
3
 
4
4
  test("pospad", () => {
5
5
  expect(pospad("1234")).toBe("1234");
@@ -17,9 +17,52 @@ test("getLength", () => {
17
17
  });
18
18
 
19
19
  test("getASN1", () => {
20
+ let pASN1;
20
21
  expect(getASN1({t: "int", v: "12ab"})).toBe("020212ab");
22
+ expect(getASN1({t: "int", v: {hex:"12ab"}})).toBe("020212ab");
21
23
  expect(getASN1({t: "seq", v: [
22
24
  {t: "int", v: "01"},
23
25
  {t: "int", v: "02"}
24
26
  ]})).toBe("3006020101020102");
27
+ pASN1 = {
28
+ t: "a4",
29
+ v: [ { t: "octstr", v: { hex: "020101" } } ]
30
+ };
31
+ expect(getASN1(pASN1)).toBe("a4050403020101");
32
+ expect(getASN1({t:"octstr",v:{hex:"020101"}})).toBe("0403020101");
33
+ pASN1 = {
34
+ t: "seq", v: [
35
+ { t: "seq", v: [
36
+ { t: "a4", v: [ { t: "octstr", v: { hex: "abcd" } } ] }
37
+ ] },
38
+ { t: "int", v: { hex: "1234" } }
39
+ ]
40
+ };
41
+ expect(getASN1(pASN1)).toBe("300c3006a4040402abcd02021234");
42
+ expect(getASN1({t:"octstr",v:{hex:"abcd"}})).toBe("0402abcd");
43
+ });
44
+
45
+ test("getASN1 - asn", () => {
46
+ expect(getASN1({t: "asn", v: { tlv: "020101" }})).toBe("020101");
47
+ });
48
+
49
+ test("getASN1 - IssuerSerial cert /C=JP/O=T1", () => {
50
+ const pASN1 = {
51
+ t: "seq", v: [
52
+ { t: "seq", v: [
53
+ { t: "a4", v: [ { t: "asn", v: { tlv: "301a310b3009060355040613024a50310b3009060355040a0c025431" } } ] }
54
+ ] },
55
+ { t: "int", v: { hex: "01" } }
56
+ ]
57
+ };
58
+ expect(getASN1(pASN1)).toBe("3023301ea41c301a310b3009060355040613024a50310b3009060355040a0c025431020101");
59
+ });
60
+
61
+
62
+ test("tagtohex", () => {
63
+ expect(tagtohex("81")).toBe("81");
64
+ expect(tagtohex("octstr")).toBe("04");
65
+ expect(tagtohex("seq")).toBe("30");
66
+ expect(tagtohex("set")).toBe("31");
67
+ expect(tagtohex("a0")).toBe("a0");
25
68
  });