diff --git a/ChangeLog.txt b/ChangeLog.txt index 43359bba..85783760 100755 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,11 @@ ChangeLog for jsrsasign +X509.getExtSubjectDirectoryAttributes bugfix +* Changes from 10.8.4 to 10.8.5 (2023-Apr-26) + - src/x509.js + - bugfix X509.getExtSubjectDirectoryAttributes method + more SubjectDirectoryExtension support * Changes from 10.8.3 to 10.8.4 (2023-Apr-26) - src/asn1x509.js diff --git a/api/files.html b/api/files.html index 21039485..82c0d132 100644 --- a/api/files.html +++ b/api/files.html @@ -896,7 +896,7 @@
1 /* x509-2.1.4.js (c) 2012-2023 Kenji Urushima | kjur.github.io/jsrsasign/license +1 /* x509-2.1.5.js (c) 2012-2023 Kenji Urushima | kjur.github.io/jsrsasign/license 2 */ 3 /* 4 * x509.js - X509 class to read subject public key from certificate. @@ -23,7 +23,7 @@ 16 * @fileOverview 17 * @name x509-1.1.js 18 * @author Kenji Urushima kenji.urushima@gmail.com - 19 * @version jsrsasign 10.8.4 x509 2.1.4 (2023-Apr-26) + 19 * @version jsrsasign 10.8.5 x509 2.1.5 (2023-Apr-26) 20 * @since jsrsasign 1.x.x 21 * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a> 22 */ @@ -2608,1338 +2608,1339 @@ 2601 var pASN1 = _ASN1HEX_parse(hExtV); 2602 for (var i = 0; i < pASN1.seq.length; i++) { 2603 var aASN1Attribute = pASN1.seq[i]; -2604 var attrType = aryval(aASN1Attribute, "0.oid"); -2605 var attrValue = aryval(aASN1Attribute, "1.set"); -2606 return { attr: attrType, array: attrValue }; -2607 } -2608 result.array = aValue; -2609 return result; -2610 } catch(ex) { -2611 throw new Error("malformed subjectDirectoryAttributes extension value"); -2612 } -2613 } -2614 -2615 // ===== BEGIN X500Name related ===================================== -2616 /* -2617 * convert ASN.1 parsed object to attrTypeAndValue assoc array<br/> -2618 * @name _convATV -2619 * @param p associative array of parsed attrTypeAndValue object -2620 * @return attrTypeAndValue associative array -2621 * @since jsrsasign 10.5.12 x509 2.0.14 -2622 * @example -2623 * _convATV({seq: [...]} &rarr: {type:"C",value:"JP",ds:"prn"} -2624 */ -2625 var _convATV = function(p) { -2626 var result = {}; -2627 try { -2628 var name = p.seq[0].oid; -2629 var oid = KJUR.asn1.x509.OID.name2oid(name); -2630 result.type = KJUR.asn1.x509.OID.oid2atype(oid); -2631 var item1 = p.seq[1]; -2632 if (item1.utf8str != undefined) { -2633 result.ds = "utf8"; -2634 result.value = item1.utf8str.str; -2635 } else if (item1.numstr != undefined) { -2636 result.ds = "num"; -2637 result.value = item1.numstr.str; -2638 } else if (item1.telstr != undefined) { -2639 result.ds = "tel"; -2640 result.value = item1.telstr.str; -2641 } else if (item1.prnstr != undefined) { -2642 result.ds = "prn"; -2643 result.value = item1.prnstr.str; -2644 } else if (item1.ia5str != undefined) { -2645 result.ds = "ia5"; -2646 result.value = item1.ia5str.str; -2647 } else if (item1.visstr != undefined) { -2648 result.ds = "vis"; -2649 result.value = item1.visstr.str; -2650 } else if (item1.bmpstr != undefined) { -2651 result.ds = "bmp"; -2652 result.value = item1.bmpstr.str; -2653 } else { -2654 throw "error"; -2655 } -2656 return result; -2657 } catch(ex) { -2658 throw new Erorr("improper ASN.1 parsed AttrTypeAndValue"); -2659 } -2660 }; -2661 -2662 /* -2663 * convert ASN.1 parsed object to RDN array<br/> -2664 * @name _convRDN -2665 * @param p associative array of parsed RDN object -2666 * @return RDN array -2667 * @since jsrsasign 10.5.12 x509 2.0.14 -2668 * @example -2669 * _convRDN({set: [...]} &rarr: [{type:"C",value:"JP",ds:"prn"}] -2670 */ -2671 var _convRDN = function(p) { -2672 try { -2673 return p.set.map(function(pATV){return _convATV(pATV)}); -2674 } catch(ex) { -2675 throw new Error("improper ASN.1 parsed RDN: " + ex); -2676 } -2677 }; -2678 -2679 /* -2680 * convert ASN.1 parsed object to X500Name array<br/> -2681 * @name _convX500Name -2682 * @param p associative array of parsed X500Name array object -2683 * @return RDN array -2684 * @since jsrsasign 10.5.12 x509 2.0.14 -2685 * @example -2686 * _convX500Name({seq: [...]} &rarr: [[{type:"C",value:"JP",ds:"prn"}]] -2687 */ -2688 var _convX500Name = function(p) { -2689 try { -2690 return p.seq.map(function(pRDN){return _convRDN(pRDN)}); -2691 } catch(ex) { -2692 throw new Error("improper ASN.1 parsed X500Name: " + ex); -2693 } -2694 }; -2695 -2696 this.getX500NameRule = function(aDN) { -2697 var isPRNRule = true; -2698 var isUTF8Rule = true; -2699 var isMixedRule = false; -2700 var logfull = ""; -2701 var logcheck = ""; -2702 var lasttag = null; -2703 -2704 var a = []; -2705 for (var i = 0; i < aDN.length; i++) { -2706 var aRDN = aDN[i]; -2707 for (var j = 0; j < aRDN.length; j++) { -2708 a.push(aRDN[j]); -2709 } -2710 } -2711 -2712 for (var i = 0; i < a.length; i++) { -2713 var item = a[i]; -2714 var tag = item.ds; -2715 var value = item.value; -2716 var type = item.type; -2717 logfull += ":" + tag; -2718 -2719 if (tag != "prn" && tag != "utf8" && tag != "ia5") { -2720 return "mixed"; -2721 } -2722 if (tag == "ia5") { -2723 if (type != "CN") { -2724 return "mixed"; -2725 } else { -2726 if (! KJUR.lang.String.isMail(value)) { -2727 return "mixed"; -2728 } else { -2729 continue; -2730 } -2731 } -2732 } -2733 if (type == "C") { -2734 if (tag == "prn") { -2735 continue; -2736 } else { -2737 return "mixed"; -2738 } -2739 } -2740 logcheck += ":" + tag; -2741 if (lasttag == null) { -2742 lasttag = tag; -2743 } else { -2744 if (lasttag !== tag) return "mixed"; -2745 } -2746 } -2747 if (lasttag == null) { -2748 return "prn"; -2749 } else { -2750 return lasttag; -2751 } -2752 }; -2753 -2754 /** -2755 * get AttributeTypeAndValue ASN.1 structure parameter as JSON object<br/> -2756 * @name getAttrTypeAndValue -2757 * @memberOf X509# -2758 * @function -2759 * @param {String} h hexadecimal string of AttributeTypeAndValue -2760 * @return {Object} JSON object of AttributeTypeAndValue parameters -2761 * @since jsrsasign 9.0.0 x509 2.0.0 -2762 * @see X509#getX500Name -2763 * @see X509#getRDN -2764 * @description -2765 * This method will get AttributeTypeAndValue parameters defined in -2766 * <a href="https://tools.ietf.org/html/rfc5280#section-4.1.2.4"> -2767 * RFC 5280 4.1.2.4</a>. -2768 * <pre> -2769 * AttributeTypeAndValue ::= SEQUENCE { -2770 * type AttributeType, -2771 * value AttributeValue } -2772 * AttributeType ::= OBJECT IDENTIFIER -2773 * AttributeValue ::= ANY -- DEFINED BY AttributeType -2774 * </pre> -2775 * <ul> -2776 * <li>{String}type - AttributeType name or OID(ex. C,O,CN)</li> -2777 * <li>{String}value - raw string of ASN.1 value of AttributeValue</li> -2778 * <li>{String}ds - DirectoryString type of AttributeValue</li> -2779 * </ul> -2780 * "ds" has one of following value: -2781 * <ul> -2782 * <li>utf8 - (0x0c) UTF8String</li> -2783 * <li>num - (0x12) NumericString</li> -2784 * <li>prn - (0x13) PrintableString</li> -2785 * <li>tel - (0x14) TeletexString</li> -2786 * <li>ia5 - (0x16) IA5String</li> -2787 * <li>vis - (0x1a) VisibleString</li> -2788 * <li>bmp - (0x1e) BMPString</li> -2789 * </ul> -2790 * @example -2791 * x = new X509(); -2792 * x.getAttrTypeAndValue("30...") → -2793 * {type:"CN",value:"john.smith@example.com",ds:"ia5"} or -2794 * {type:"O",value:"Sample Corp.",ds:"prn"} -2795 */ -2796 // unv - (0x1c??) UniversalString ... for future -2797 this.getAttrTypeAndValue = function(h) { -2798 var p = _ASN1HEX_parse(h); -2799 return _convATV(p); -2800 }; -2801 -2802 /** -2803 * get RelativeDistinguishedName ASN.1 structure parameter array<br/> -2804 * @name getRDN -2805 * @memberOf X509# -2806 * @function -2807 * @param {String} h hexadecimal string of RDN -2808 * @return {Array} array of AttrTypeAndValue parameters -2809 * @since jsrsasign 9.0.0 x509 2.0.0 -2810 * @see X509#getX500Name -2811 * @see X509#getRDN -2812 * @see X509#getAttrTypeAndValue -2813 * @description -2814 * This method will get RelativeDistinguishedName parameters defined in -2815 * <a href="https://tools.ietf.org/html/rfc5280#section-4.1.2.4"> -2816 * RFC 5280 4.1.2.4</a>. -2817 * <pre> -2818 * RelativeDistinguishedName ::= -2819 * SET SIZE (1..MAX) OF AttributeTypeAndValue -2820 * </pre> -2821 * @example -2822 * x = new X509(); -2823 * x.getRDN("31...") → -2824 * [{type:"C",value:"US",ds:"prn"}] or -2825 * [{type:"O",value:"Sample Corp.",ds:"prn"}] or -2826 * [{type:"CN",value:"john.smith@example.com",ds:"ia5"}] -2827 */ -2828 this.getRDN = function(h) { -2829 var p = _ASN1HEX_parse(h); -2830 return _convRDN(p); -2831 }; -2832 -2833 /** -2834 * get X.500 Name ASN.1 structure parameter array<br/> -2835 * @name getX500NameArray -2836 * @memberOf X509# -2837 * @function -2838 * @param {String} h hexadecimal string of Name -2839 * @return {Array} array of RDN parameter array -2840 * @since jsrsasign 10.0.6 x509 2.0.9 -2841 * @see X509#getX500Name -2842 * @see X509#getRDN -2843 * @see X509#getAttrTypeAndValue -2844 * @description -2845 * This method will get Name parameter defined in -2846 * <a href="https://tools.ietf.org/html/rfc5280#section-4.1.2.4"> -2847 * RFC 5280 4.1.2.4</a>. -2848 * <pre> -2849 * Name ::= CHOICE { -- only one possibility for now -- -2850 * rdnSequence RDNSequence } -2851 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName -2852 * </pre> -2853 * @example -2854 * x = new X509(); -2855 * x.getX500NameArray("30...") → -2856 * [[{type:"C",value:"US",ds:"prn"}], -2857 * [{type:"O",value:"Sample Corp.",ds:"utf8"}], -2858 * [{type:"CN",value:"john.smith@example.com",ds:"ia5"}]] -2859 */ -2860 this.getX500NameArray = function(h) { -2861 var p = _ASN1HEX_parse(h); -2862 return _convX500Name(p); -2863 }; -2864 -2865 /** -2866 * get Name ASN.1 structure parameter array<br/> -2867 * @name getX500Name -2868 * @memberOf X509# -2869 * @function -2870 * @param {String} h hexadecimal string of Name -2871 * @param {boolean} flagCanon flag to conclude canonicalized name (DEFAULT false) -2872 * @param {boolean} flagHex flag to conclude hexadecimal string (DEFAULT false) -2873 * @return {Array} array of RDN parameter array -2874 * @since jsrsasign 9.0.0 x509 2.0.0 -2875 * @see X509#getX500NameArray -2876 * @see X509#getRDN -2877 * @see X509#getAttrTypeAndValue -2878 * @see X509#c14nRDNArray -2879 * @see KJUR.asn1.x509.X500Name -2880 * @see KJUR.asn1.x509.GeneralName -2881 * @see KJUR.asn1.x509.GeneralNames -2882 * -2883 * @description -2884 * This method will get Name parameter defined in -2885 * <a href="https://tools.ietf.org/html/rfc5280#section-4.1.2.4"> -2886 * RFC 5280 4.1.2.4</a>. -2887 * <pre> -2888 * Name ::= CHOICE { -- only one possibility for now -- -2889 * rdnSequence RDNSequence } -2890 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName -2891 * </pre> -2892 * <br> -2893 * NOTE: From jsrsasign 10.6.0, flagHex and flagCanon has been -2894 * supported to conclude a canonicalized name for caseIgnoreMatch -2895 * desribed in <a href="https://tools.ietf.org/html/rfc4518"> -2896 * RFC 4518</a>. -2897 * -2898 * @example -2899 * x = new X509(); -2900 * x.getX500Name("30...") → -2901 * { array: [ -2902 * [{type:"C",value:"US",ds:"prn"}], -2903 * [{type:"O",value:"Sample Corp.",ds:"utf8"}], -2904 * [{type:"CN",value:"john.smith@example.com",ds:"ia5"}] -2905 * ], -2906 * str: "/C=US/O=Sample Corp./CN=john.smith@example.com", -2907 * hex: "30..." } -2908 * -2909 * x.getX500Name("30...", true) → -2910 * { array: [ -2911 * [{type:"C",value:"US",ds:"prn"}], -2912 * [{type:"O",value:"Sample Corp.",ds:"utf8"}] -2913 * ], -2914 * str: "/C=US/O=Sample Corp.", -2915 * canon: "/c=us/o=sample corp.", -2916 * hex: "30..." } -2917 */ -2918 this.getX500Name = function(h, flagCanon, flagHex) { -2919 var a = this.getX500NameArray(h); -2920 var s = this.dnarraytostr(a); -2921 var result = { str: s }; -2922 -2923 result.array = a; -2924 if (flagHex == true) result.hex = h; -2925 if (flagCanon == true) result.canon = this.c14nRDNArray(a); -2926 return result; -2927 }; -2928 -2929 // ===== END X500Name related ===================================== -2930 -2931 // ===== BEGIN read certificate ===================================== -2932 /** -2933 * read PEM formatted X.509 certificate from string.<br/> -2934 * @name readCertPEM -2935 * @memberOf X509# -2936 * @function -2937 * @param {String} sCertPEM string for PEM formatted X.509 certificate -2938 * @example -2939 * x = new X509(); -2940 * x.readCertPEM(sCertPEM); // read certificate -2941 */ -2942 this.readCertPEM = function(sCertPEM) { -2943 this.readCertHex(_pemtohex(sCertPEM)); -2944 }; -2945 -2946 /** -2947 * read a hexadecimal string of X.509 certificate<br/> -2948 * @name readCertHex -2949 * @memberOf X509# -2950 * @function -2951 * @param {String} sCertHex hexadecimal string of X.509 certificate -2952 * @since jsrsasign 7.1.4 x509 1.1.13 -2953 * @description -2954 * NOTE: {@link X509#parseExt} will called internally since jsrsasign 7.2.0. -2955 * @example -2956 * x = new X509(); -2957 * x.readCertHex("3082..."); // read certificate -2958 */ -2959 this.readCertHex = function(sCertHex) { -2960 this.hex = sCertHex; -2961 this.getVersion(); // set version parameter -2962 -2963 try { -2964 _getIdxbyList(this.hex, 0, [0, 7], "a3"); // has [3] v3ext -2965 this.parseExt(); -2966 } catch(ex) {}; -2967 }; -2968 -2969 // ===== END read certificate ===================================== -2970 -2971 /** -2972 * get JSON object of certificate parameters<br/> -2973 * @name getParam -2974 * @memberOf X509# -2975 * @function -2976 * @param {Object} option optional setting for return object -2977 * @return {Object} JSON object of certificate parameters -2978 * @since jsrsasign 9.0.0 x509 2.0.0 -2979 * @see KJUR.asn1.x509.X509Util.newCertPEM -2980 * -2981 * @description -2982 * This method returns a JSON object of the certificate -2983 * parameters. Return value can be passed to -2984 * {@link KJUR.asn1.x509.X509Util.newCertPEM}. -2985 * <br/> -2986 * NOTE1: From jsrsasign 10.5.16, optional argument can be applied. -2987 * It can have following members: -2988 * <ul> -2989 * <li>tbshex - (boolean) tbshex member with hex value of -2990 * tbsCertificate will be added if true (DEFAULT undefined)</li> -2991 * <li>nodnarray - (boolean) array member for subject and -2992 * issuer will be deleted to simplify it if true (DEFAULT undefined)<li> -2993 * <li>dncanon - (boolean) add canon member to subject and issuer for DN StringPrep if true(DEFAULT undefined)</li> -2994 * <li>dnhex - (boolean) add hex member to subject and issuer if true(DEFAULT undefined)</li> -2995 * </ul> -2996 * <br/> -2997 * NOTE2: From jsrsasign 10.6.0, member "dncanon" and "dnhex" supported -2998 * in the "option" argument. -2999 * -3000 * @example -3001 * x = new X509(); -3002 * x.readCertPEM("-----BEGIN CERTIFICATE..."); -3003 * x.getParam() → -3004 * {version:3, -3005 * serial:{hex:"12ab"}, -3006 * sigalg:"SHA256withRSA", -3007 * issuer: {array:[[{type:'CN',value:'CA1',ds:'prn'}]],str:"/O=CA1"}, -3008 * notbefore:"160403023700Z", -3009 * notafter:"160702023700Z", -3010 * subject: {array:[[{type:'CN',value:'Test1',ds:'prn'}]],str:"/CN=Test1"}, -3011 * sbjpubkey:"-----BEGIN PUBLIC KEY...", -3012 * ext:[ -3013 * {extname:"keyUsage",critical:true,names:["digitalSignature"]}, -3014 * {extname:"basicConstraints",critical:true}, -3015 * {extname:"subjectKeyIdentifier",kid:{hex:"f2eb..."}}, -3016 * {extname:"authorityKeyIdentifier",kid:{hex:"12ab..."}}, -3017 * {extname:"authorityInfoAccess",array:[{ocsp:"http://ocsp.example.com/"}]}, -3018 * {extname:"certificatePolicies",array:[{policyoid:"2.23.140.1.2.1"}]} -3019 * ], -3020 * sighex:"0b76...8" -3021 * }; -3022 * -3023 * x.getParam({tbshex: true}) → { ... , tbshex: "30..." } -3024 * x.getParam({nodnarray: true}) → {issuer: {str: "/C=JP"}, ...} -3025 * x.getParam({dncanon: true}) → {... {issuer: {canon: "/c=jp/o=..."} ...} ...} -3026 * x.getParam({dnhex: true}) → {... {issuer: {hex: "30..."} ...} ...} -3027 */ -3028 this.getParam = function(option) { -3029 var result = {}; -3030 if (option == undefined) option = {}; -3031 -3032 result.version = this.getVersion(); -3033 result.serial = {hex: this.getSerialNumberHex()}; -3034 result.sigalg = this.getSignatureAlgorithmField(); -3035 result.issuer = this.getIssuer(option.dncanon, option.dnhex); -3036 result.notbefore = this.getNotBefore(); -3037 result.notafter = this.getNotAfter(); -3038 result.subject = this.getSubject(option.dncanon, option.dnhex); -3039 result.sbjpubkey = hextopem(this.getPublicKeyHex(), "PUBLIC KEY"); -3040 if (this.aExtInfo != undefined && -3041 this.aExtInfo.length > 0) { -3042 result.ext = this.getExtParamArray(); -3043 } -3044 result.sighex = this.getSignatureValueHex(); -3045 -3046 // for options -3047 if (option.tbshex == true) { -3048 result.tbshex = _getTLVbyList(this.hex, 0, [0]); -3049 } -3050 if (option.nodnarray == true) { -3051 delete result.issuer.array; -3052 delete result.subject.array; -3053 } -3054 -3055 return result; -3056 }; -3057 -3058 /** -3059 * get array of certificate extension parameter JSON object<br/> -3060 * @name getExtParamArray -3061 * @memberOf X509# -3062 * @function -3063 * @param {String} hExtSeq hexadecimal string of SEQUENCE of Extension -3064 * @return {Array} array of certificate extension parameter JSON object -3065 * @since jsrsasign 9.0.0 x509 2.0.0 -3066 * @see KJUR.asn1.x509.X509Util.newCertPEM -3067 * @see X509#getParam -3068 * @see X509#getExtParam -3069 * @see X509CRL#getParam -3070 * @see KJUR.asn1.csr.CSRUtil.getParam -3071 * -3072 * @description -3073 * This method returns an array of certificate extension -3074 * parameters. -3075 * <br/> -3076 * NOTE: Argument "hExtSeq" have been supported since jsrsasign 9.1.1. -3077 * -3078 * @example -3079 * x = new X509(); -3080 * x.readCertPEM("-----BEGIN CERTIFICATE..."); -3081 * x.getExtParamArray() → -3082 * [ {extname:"keyUsage",critical:true,names:["digitalSignature"]}, -3083 * {extname:"basicConstraints",critical:true}, -3084 * {extname:"subjectKeyIdentifier",kid:{hex:"f2eb..."}}, -3085 * {extname:"authorityKeyIdentifier",kid:{hex:"12ab..."}}, -3086 * {extname:"authorityInfoAccess",array:[{ocsp:"http://ocsp.example.com/"}]}, -3087 * {extname:"certificatePolicies",array:[{policyoid:"2.23.140.1.2.1"}]}] -3088 */ -3089 this.getExtParamArray = function(hExtSeq) { -3090 if (hExtSeq == undefined) { -3091 // for X.509v3 certificate -3092 var idx1 = _getIdxbyListEx(this.hex, 0, [0, "[3]"]); -3093 if (idx1 != -1) { -3094 hExtSeq = _getTLVbyListEx(this.hex, 0, [0, "[3]", 0], "30"); -3095 } -3096 } -3097 var result = []; -3098 var aIdx = _getChildIdx(hExtSeq, 0); -3099 -3100 for (var i = 0; i < aIdx.length; i++) { -3101 var hExt = _getTLV(hExtSeq, aIdx[i]); -3102 var extParam = this.getExtParam(hExt); -3103 if (extParam != null) result.push(extParam); -3104 } -3105 -3106 return result; -3107 }; -3108 -3109 /** -3110 * get a extension parameter JSON object<br/> -3111 * @name getExtParam -3112 * @memberOf X509# -3113 * @function -3114 * @param {String} hExt hexadecimal string of Extension -3115 * @return {Array} Extension parameter JSON object -3116 * @since jsrsasign 9.1.1 x509 2.0.1 -3117 * @see KJUR.asn1.x509.X509Util.newCertPEM -3118 * @see X509#getParam -3119 * @see X509#getExtParamArray -3120 * @see X509CRL#getParam -3121 * @see KJUR.asn1.csr.CSRUtil.getParam -3122 * -3123 * @description -3124 * This method returns a extension parameters as JSON object. -3125 * -3126 * @example -3127 * x = new X509(); -3128 * ... -3129 * x.getExtParam("30...") → -3130 * {extname:"keyUsage",critical:true,names:["digitalSignature"]} -3131 */ -3132 this.getExtParam = function(hExt) { -3133 var result = {}; -3134 var aIdx = _getChildIdx(hExt, 0); -3135 var aIdxLen = aIdx.length; -3136 if (aIdxLen != 2 && aIdxLen != 3) -3137 throw new Error("wrong number elements in Extension: " + -3138 aIdxLen + " " + hExt); -3139 -3140 var oid = _hextooidstr(_getVbyList(hExt, 0, [0], "06")); -3141 -3142 var critical = false; -3143 if (aIdxLen == 3 && _getTLVbyList(hExt, 0, [1]) == "0101ff") -3144 critical = true; -3145 -3146 var hExtV = _getTLVbyList(hExt, 0, [aIdxLen - 1, 0]); -3147 -3148 var extParam = undefined; -3149 if (oid == "2.5.29.14") { -3150 extParam = this.getExtSubjectKeyIdentifier(hExtV, critical); -3151 } else if (oid == "2.5.29.15") { -3152 extParam = this.getExtKeyUsage(hExtV, critical); -3153 } else if (oid == "2.5.29.17") { -3154 extParam = this.getExtSubjectAltName(hExtV, critical); -3155 } else if (oid == "2.5.29.18") { -3156 extParam = this.getExtIssuerAltName(hExtV, critical); -3157 } else if (oid == "2.5.29.19") { -3158 extParam = this.getExtBasicConstraints(hExtV, critical); -3159 } else if (oid == "2.5.29.30") { -3160 extParam = this.getExtNameConstraints(hExtV, critical); -3161 } else if (oid == "2.5.29.31") { -3162 extParam = this.getExtCRLDistributionPoints(hExtV, critical); -3163 } else if (oid == "2.5.29.32") { -3164 extParam = this.getExtCertificatePolicies(hExtV, critical); -3165 } else if (oid == "2.5.29.33") { -3166 extParam = this.getExtPolicyMappings(hExtV, critical); -3167 } else if (oid == "2.5.29.35") { -3168 extParam = this.getExtAuthorityKeyIdentifier(hExtV, critical); -3169 } else if (oid == "2.5.29.36") { -3170 extParam = this.getExtPolicyConstraints(hExtV, critical); -3171 } else if (oid == "2.5.29.37") { -3172 extParam = this.getExtExtKeyUsage(hExtV, critical); -3173 } else if (oid == "2.5.29.54") { -3174 extParam = this.getExtInhibitAnyPolicy(hExtV, critical); -3175 } else if (oid == "1.3.6.1.5.5.7.1.1") { -3176 extParam = this.getExtAuthorityInfoAccess(hExtV, critical); -3177 } else if (oid == "2.5.29.20") { -3178 extParam = this.getExtCRLNumber(hExtV, critical); -3179 } else if (oid == "2.5.29.21") { -3180 extParam = this.getExtCRLReason(hExtV, critical); -3181 } else if (oid == "2.5.29.9") { -3182 extParam = this.getExtSubjectDirectoryAttributes(hExtV, critical); -3183 } else if (oid == "1.3.6.1.5.5.7.48.1.2") { -3184 extParam = this.getExtOcspNonce(hExtV, critical); -3185 } else if (oid == "1.3.6.1.5.5.7.48.1.5") { -3186 extParam = this.getExtOcspNoCheck(hExtV, critical); -3187 } else if (oid == "1.2.840.113583.1.1.9.1") { -3188 extParam = this.getExtAdobeTimeStamp(hExtV, critical); -3189 } else if (X509.EXT_PARSER[oid] != undefined) { -3190 extParam = X509.EXT_PARSER[oid](oid, critical, hExtV); -3191 } -3192 if (extParam != undefined) return extParam; -3193 -3194 // for private or unsupported extension -3195 var privateParam = { extname: oid, extn: hExtV }; -3196 try { -3197 privateParam.extn = _ASN1HEX_parse(hExtV); -3198 } catch(ex) {} -3199 if (critical) privateParam.critical = true; -3200 return privateParam; -3201 }; -3202 -3203 /** -3204 * find extension parameter in array<br/> -3205 * @name findExt -3206 * @memberOf X509# -3207 * @function -3208 * @param {Array} aExt array of extension parameters -3209 * @param {String} extname extension name -3210 * @return {Array} extension parameter in the array or null -3211 * @since jsrsasign 10.0.3 x509 2.0.7 -3212 * @see X509#getParam -3213 * -3214 * @description -3215 * This method returns an extension parameter for -3216 * specified extension name in the array. -3217 * This method is useful to update extension parameter value. -3218 * When there is no such extension with the extname, -3219 * this returns "null". -3220 * -3221 * @example -3222 * // (1) -3223 * x = new X509(CERTPEM); -3224 * params = x.getParam(); -3225 * pSKID = x.findExt(params.ext, "subjectKeyIdentifier"); -3226 * pSKID.kid = "1234abced..."; // skid in the params is updated. -3227 * // then params was updated -3228 * -3229 * // (2) another example -3230 * aExt = [ -3231 * {extname:"keyUsage",critical:true,names:["digitalSignature"]}, -3232 * {extname:"basicConstraints",critical:true}, -3233 * {extname:"subjectKeyIdentifier",kid:{hex:"f2eb..."}}, -3234 * {extname:"authorityKeyIdentifier",kid:{hex:"12ab..."}}, -3235 * {extname:"authorityInfoAccess",array:[{ocsp:"http://ocsp.example.com/"}]}, -3236 * {extname:"certificatePolicies",array:[{policyoid:"2.23.140.1.2.1"}]} -3237 * ]; -3238 * var x = new X509(); -3239 * x.findExt(aExt, "authorityKeyInfoAccess").array[0].ocsp = "http://aaa.com"; -3240 * pKU = x.findExt(aExt, "keyUsage"); -3241 * delete pKU["critical"]; // clear criticla flag -3242 * pKU.names = ["keyCertSign", "cRLSign"]; -3243 * // then aExt was updated -3244 */ -3245 this.findExt = function(aExt, extname) { -3246 for (var i = 0; i < aExt.length; i++) { -3247 if (aExt[i].extname == extname) return aExt[i]; -3248 } -3249 return null; -3250 -3251 }; -3252 -3253 /** -3254 * update CRLDistributionPoints Full URI in parameter<br/> -3255 * @name updateCDPFullURI -3256 * @memberOf X509# -3257 * @function -3258 * @param {Array} aExt array of extension parameters -3259 * @param {String} newURI string of new uri -3260 * @since jsrsasign 10.0.4 x509 2.0.8 -3261 * @see X509#findExt -3262 * @see KJUR.asn1.x509.CRLDistributionPoints -3263 * -3264 * @description -3265 * This method updates Full URI of CRLDistributionPoints extension -3266 * in the extension parameter array if it exists. -3267 * -3268 * @example -3269 * aExt = [ -3270 * {extname:"authorityKeyIdentifier",kid:{hex:"12ab..."}}, -3271 * {extname:"cRLDistributionPoints", -3272 * array:[{dpname:{full:[{uri:"http://example.com/a.crl"}]}}]}, -3273 * ]; -3274 * x = new X509(); -3275 * x.updateCDPFullURI(aExt, "http://crl2.example.new/b.crl"); -3276 */ -3277 this.updateExtCDPFullURI = function(aExt, newURI) { -3278 var pExt = this.findExt(aExt, "cRLDistributionPoints"); -3279 if (pExt == null) return; -3280 if (pExt.array == undefined) return; -3281 var aDP = pExt.array; -3282 for (var i = 0; i < aDP.length; i++) { -3283 if (aDP[i].dpname == undefined) continue; -3284 if (aDP[i].dpname.full == undefined) continue; -3285 var aURI = aDP[i].dpname.full; -3286 for (var j = 0; j < aURI.length; j++) { -3287 var pURI = aURI[i]; -3288 if (pURI.uri == undefined) continue; -3289 pURI.uri = newURI; -3290 } -3291 } -3292 }; -3293 -3294 /** -3295 * update authorityInfoAccess ocsp in parameter<br/> -3296 * @name updateAIAOCSP -3297 * @memberOf X509# -3298 * @function -3299 * @param {Array} aExt array of extension parameters -3300 * @param {String} newURI string of new uri -3301 * @since jsrsasign 10.0.4 x509 2.0.8 -3302 * @see X509#findExt -3303 * @see KJUR.asn1.x509.AuthorityInfoAccess -3304 * -3305 * @description -3306 * This method updates "ocsp" accessMethod URI of -3307 * AuthorityInfoAccess extension -3308 * in the extension parameter array if it exists. -3309 * -3310 * @example -3311 * aExt = [ -3312 * {extname:"authorityKeyIdentifier",kid:{hex:"12ab..."}}, -3313 * {extname:"authoriyInfoAccess", -3314 * array:[ -3315 * {ocsp: "http://ocsp1.example.com"}, -3316 * {caissuer: "http://example.com/a.crt"} -3317 * ]} -3318 * ]; -3319 * x = new X509(); -3320 * x.updateAIAOCSP(aExt, "http://ocsp2.example.net"); -3321 */ -3322 this.updateExtAIAOCSP = function(aExt, newURI) { -3323 var pExt = this.findExt(aExt, "authorityInfoAccess"); -3324 if (pExt == null) return; -3325 if (pExt.array == undefined) return; -3326 var a = pExt.array; -3327 for (var i = 0; i < a.length; i++) { -3328 if (a[i].ocsp != undefined) a[i].ocsp = newURI; -3329 } -3330 }; -3331 -3332 /** -3333 * update authorityInfoAccess caIssuer in parameter<br/> -3334 * @name updateAIACAIssuer -3335 * @memberOf X509# -3336 * @function -3337 * @param {Array} aExt array of extension parameters -3338 * @param {String} newURI string of new uri -3339 * @since jsrsasign 10.0.4 x509 2.0.8 -3340 * @see X509#findExt -3341 * @see KJUR.asn1.x509.AuthorityInfoAccess -3342 * -3343 * @description -3344 * This method updates "caIssuer" accessMethod URI of -3345 * AuthorityInfoAccess extension -3346 * in the extension parameter array if it exists. -3347 * -3348 * @example -3349 * aExt = [ -3350 * {extname:"authorityKeyIdentifier",kid:{hex:"12ab..."}}, -3351 * {extname:"authoriyInfoAccess", -3352 * array:[ -3353 * {ocsp: "http://ocsp1.example.com"}, -3354 * {caissuer: "http://example.com/a.crt"} -3355 * ]} -3356 * ]; -3357 * x = new X509(); -3358 * x.updateAIACAIssuer(aExt, "http://example.net/b.crt"); -3359 */ -3360 this.updateExtAIACAIssuer = function(aExt, newURI) { -3361 var pExt = this.findExt(aExt, "authorityInfoAccess"); -3362 if (pExt == null) return; -3363 if (pExt.array == undefined) return; -3364 var a = pExt.array; -3365 for (var i = 0; i < a.length; i++) { -3366 if (a[i].caissuer != undefined) a[i].caissuer = newURI; -3367 } -3368 }; -3369 -3370 /** -3371 * convert array for X500 distinguish name to distinguish name string<br/> -3372 * @name dnarraytostr -3373 * @memberOf X509# -3374 * @function -3375 * @param {Array} aDN array for X500 distinguish name -3376 * @return {String} distinguish name -3377 * @since jsrsasign 10.0.6 x509 2.0.8 -3378 * @see X509#getX500Name -3379 * @see X509#getX500NameArray -3380 * @see KJUR.asn1.x509.X500Name -3381 * -3382 * @description -3383 * This method converts from an array representation of -3384 * X.500 distinguished name to X.500 name string. -3385 * This supports multi-valued RDN. -3386 * -3387 * @example -3388 * var x = new X509(); -3389 * x.dnarraytostr( -3390 * [[{type:"C",value:"JP",ds:"prn"}], -3391 * [{type:"O",value:"T1",ds:"prn"}]]) → "/C=JP/O=T1" -3392 * x.dnarraytostr( -3393 * [[{type:"C",value:"JP",ds:"prn"}], -3394 * [{type:"O",value:"T1",ds:"prn"} -3395 * {type:"CN",value:"Bob",ds:"prn"}]]) → "/C=JP/O=T1+CN=Bob" -3396 */ -3397 this.dnarraytostr = function(aDN) { -3398 function rdnarraytostr(aRDN) { -3399 return aRDN.map(function(x){return atvtostr(x).replace(/\+/,"\\+");}).join("+"); -3400 }; -3401 -3402 function atvtostr(pATV) { -3403 return pATV.type + "=" + pATV.value; -3404 }; -3405 -3406 return "/" + aDN.map(function(x){return rdnarraytostr(x).replace(/\//, "\\/");}).join("/"); -3407 }; -3408 -3409 /** -3410 * set canonicalized DN to a DN parameter<br/> -3411 * @name setCanonicalizedDN -3412 * @memberOf X509# -3413 * @function -3414 * @param {object} pDN DN parameter associative array -3415 * @since jsrsasign 10.6.0 x509 2.1.0 -3416 * -3417 * @description -3418 * This method canonicalizes a DN string as following: -3419 * <ul> -3420 * <li>convert to lower case</li> -3421 * <li>convert from all multiple spaces to a space</li> -3422 * </ul> -3423 * -3424 * @example -3425 * var x = new X509(); -3426 * var pDN = { -3427 * array: [ -3428 * [{type:'C',value:'JP',ds:'prn'}], -3429 * [{type:'O',value:'Test 1',ds:'prn'}] ], -3430 * str: "/C=JP/O=Test 1" }; -3431 * x.setCanonicalizedDN(pDN); -3432 -3433 * // pDN will become following -3434 * pDN = { -3435 * array: [ -3436 * [{type:'C',value:'JP',ds:'prn'}], -3437 * [{type:'O',value:'Test 1',ds:'prn'}] ], -3438 * str: "/C=JP/O=Test 1", -3439 * canon: "/c=jp/o=test 1" }; -3440 */ -3441 this.setCanonicalizedDN = function(pDN) { -3442 var aRDN; -3443 if (pDN.str != undefined && pDN.array == undefined) { -3444 var dDN = new KJUR.asn1.x509.X500Name({str: pDN.str}); -3445 var hDN = dDN.tohex(); -3446 aRDN = this.getX500NameArray(hDN); -3447 } else { -3448 aRDN = pDN.array; -3449 } -3450 if (pDN.canon == undefined) { -3451 pDN.canon = this.c14nRDNArray(aRDN); -3452 } -3453 }; -3454 -3455 /** -3456 * simple canonicalization(c14n) for RDN array<br/> -3457 * @name c14nRDNArray -3458 * @memberOf X509# -3459 * @function -3460 * @param {array} aRDN array of RDN parameters -3461 * @return {string} canonicalized distinguish name (ex. "/c=jp/o=test ca") -3462 * @since jsrsasign 10.6.0 x509 2.1.0 -3463 * -3464 * @description -3465 * This method canonicalizes a DN string according to -3466 * <a href="https://datatracker.ietf.org/doc/html/rfc4518#appendix-B"> -3467 * "RFC 4518 StringPrep Appendix B Substring Matching"</a> as following: -3468 * <ul> -3469 * <li>convert to lower case</li> -3470 * <li>convert from all sequence of spaces to a space</li> -3471 * <li>remove leading and trailing spaces</li> -3472 * </ul> -3473 * -3474 * @example -3475 * var x = new X509(); -3476 * x.c14nRDNArray([ -3477 * [{type:"C", value:"JP", ds: "prn"}], -3478 * [{type:"O", value:" Test 1234 ", ds: "utf8"}], -3479 * [{type:"OU", value:"HR 45", ds: "utf8"}] -3480 * ]) → "/c=jp/o=test 1234/ou=hr 45" -3481 */ -3482 this.c14nRDNArray = function(aRDN) { -3483 var a = []; -3484 for (var i = 0; i < aRDN.length; i++) { -3485 var aAVA = aRDN[i]; -3486 var a2 = []; -3487 for (var j = 0; j < aAVA.length; j++) { -3488 var pAVA = aAVA[j]; -3489 var value = pAVA.value; -3490 value = value.replace(/^\s*/, ''); -3491 value = value.replace(/\s*$/, ''); -3492 value = value.replace(/\s+/g, ' '); -3493 value = value.toLowerCase(); -3494 a2.push(pAVA.type.toLowerCase() + "=" + value); -3495 } -3496 a.push(a2.join("+")); -3497 } -3498 return "/" + a.join("/"); -3499 }; -3500 -3501 /** -3502 * get certificate information as string.<br/> -3503 * @name getInfo -3504 * @memberOf X509# -3505 * @function -3506 * @return {String} certificate information string -3507 * @since jsrsasign 5.0.10 x509 1.1.8 -3508 * @example -3509 * x = new X509(); -3510 * x.readCertPEM(certPEM); -3511 * console.log(x.getInfo()); -3512 * // this shows as following -3513 * Basic Fields -3514 * serial number: 02ac5c266a0b409b8f0b79f2ae462577 -3515 * signature algorithm: SHA1withRSA -3516 * issuer: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA -3517 * notBefore: 061110000000Z -3518 * notAfter: 311110000000Z -3519 * subject: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA -3520 * subject public key info: -3521 * key algorithm: RSA -3522 * n=c6cce573e6fbd4bb... -3523 * e=10001 -3524 * X509v3 Extensions: -3525 * keyUsage CRITICAL: -3526 * digitalSignature,keyCertSign,cRLSign -3527 * basicConstraints CRITICAL: -3528 * cA=true -3529 * subjectKeyIdentifier : -3530 * b13ec36903f8bf4701d498261a0802ef63642bc3 -3531 * authorityKeyIdentifier : -3532 * kid=b13ec36903f8bf4701d498261a0802ef63642bc3 -3533 * signature algorithm: SHA1withRSA -3534 * signature: 1c1a0697dcd79c9f... -3535 */ -3536 this.getInfo = function() { -3537 var _getSubjectAltNameStr = function(params) { -3538 var s = ""; -3539 var indent = " "; -3540 var NL = "\n"; -3541 var a = params.array; -3542 for (var i = 0; i < a.length; i++) { -3543 var pGN = a[i]; -3544 if (pGN.dn != undefined) s += indent + "dn: " + pGN.dn.str + NL; -3545 if (pGN.ip != undefined) s += indent + "ip: " + pGN.ip + NL; -3546 if (pGN.rfc822 != undefined) s += indent + "rfc822: " + pGN.rfc822 + NL; -3547 if (pGN.dns != undefined) s += indent + "dns: " + pGN.dns + NL; -3548 if (pGN.uri != undefined) s += indent + "uri: " + pGN.uri + NL; -3549 if (pGN.other != undefined) { -3550 var oidname = pGN.other.oid; -3551 var value = JSON.stringify(pGN.other.value).replace(/\"/g, ''); -3552 s += indent + "other: " + oidname + "=" + value + NL; -3553 } -3554 } -3555 s = s.replace(/\n$/, ''); -3556 return s; -3557 }; -3558 var _getCertificatePoliciesStr = function(params) { -3559 var s = ""; -3560 var a = params.array; -3561 for (var i = 0; i < a.length; i++) { -3562 var pi = a[i]; -3563 s += " policy oid: " + pi.policyoid + "\n"; -3564 if (pi.array === undefined) continue; -3565 for (var j = 0; j < pi.array.length; j++) { -3566 var pqi = pi.array[j]; -3567 if (pqi.cps !== undefined) { -3568 s += " cps: " + pqi.cps + "\n"; -3569 } -3570 } -3571 } -3572 return s; -3573 }; -3574 var _getCRLDistributionPointsStr = function(params) { -3575 var s = ""; -3576 var a = params.array; -3577 for (var i = 0; i < a.length; i++) { -3578 var dp = a[i]; -3579 try { -3580 if (dp.dpname.full[0].uri !== undefined) -3581 s += " " + dp.dpname.full[0].uri + "\n"; -3582 } catch(ex) {}; -3583 try { -3584 if (dp.dname.full[0].dn.hex !== undefined) -3585 s += " " + X509.hex2dn(dp.dpname.full[0].dn.hex) + "\n"; -3586 } catch(ex) {}; -3587 } -3588 return s; -3589 } -3590 var _getAuthorityInfoAccessStr = function(params) { -3591 var s = ""; -3592 var a = params.array; -3593 for (var i = 0; i < a.length; i++) { -3594 var ad = a[i]; -3595 -3596 if (ad.caissuer !== undefined) -3597 s += " caissuer: " + ad.caissuer + "\n"; -3598 if (ad.ocsp !== undefined) -3599 s += " ocsp: " + ad.ocsp + "\n"; -3600 } -3601 return s; -3602 }; -3603 var _X509 = X509; -3604 var s, pubkey, aExt; -3605 s = "Basic Fields\n"; -3606 s += " serial number: " + this.getSerialNumberHex() + "\n"; -3607 s += " signature algorithm: " + this.getSignatureAlgorithmField() + "\n"; -3608 s += " issuer: " + this.getIssuerString() + "\n"; -3609 s += " notBefore: " + this.getNotBefore() + "\n"; -3610 s += " notAfter: " + this.getNotAfter() + "\n"; -3611 s += " subject: " + this.getSubjectString() + "\n"; -3612 s += " subject public key info: " + "\n"; -3613 -3614 // subject public key info -3615 pubkey = this.getPublicKey(); -3616 s += " key algorithm: " + pubkey.type + "\n"; -3617 -3618 if (pubkey.type === "RSA") { -3619 s += " n=" + hextoposhex(pubkey.n.toString(16)).substr(0, 16) + "...\n"; -3620 s += " e=" + hextoposhex(pubkey.e.toString(16)) + "\n"; -3621 } -3622 -3623 // X.509v3 Extensions -3624 aExt = this.aExtInfo; -3625 -3626 if (aExt !== undefined && aExt !== null) { -3627 s += "X509v3 Extensions:\n"; -3628 -3629 for (var i = 0; i < aExt.length; i++) { -3630 var info = aExt[i]; -3631 -3632 // show extension name and critical flag -3633 var extName = KJUR.asn1.x509.OID.oid2name(info["oid"]); -3634 if (extName === '') extName = info["oid"]; -3635 -3636 var critical = ''; -3637 if (info["critical"] === true) critical = "CRITICAL"; -3638 -3639 s += " " + extName + " " + critical + ":\n"; -3640 -3641 // show extension value if supported -3642 if (extName === "basicConstraints") { -3643 var bc = this.getExtBasicConstraints(); -3644 if (bc.cA === undefined) { -3645 s += " {}\n"; -3646 } else { -3647 s += " cA=true"; -3648 if (bc.pathLen !== undefined) -3649 s += ", pathLen=" + bc.pathLen; -3650 s += "\n"; -3651 } -3652 } else if (extName == "policyMappings") { -3653 var a = this.getExtPolicyMappings().array; -3654 var sMap = a.map(function(item){ -3655 var aPolicy = item; -3656 return aPolicy[0] + ":" + aPolicy[1]; -3657 }).join(", "); -3658 s += " " + sMap + "\n"; -3659 } else if (extName == "policyConstraints") { -3660 var p = this.getExtPolicyConstraints(); -3661 s += " "; -3662 if (p.reqexp != undefined) s += " reqexp=" + p.reqexp; -3663 if (p.inhibit != undefined) s += " inhibit=" + p.inhibit; -3664 s += "\n"; -3665 } else if (extName == "inhibitAnyPolicy") { -3666 var p = this.getExtInhibitAnyPolicy(); -3667 s += " skip=" + p.skip + "\n"; -3668 } else if (extName == "keyUsage") { -3669 s += " " + this.getExtKeyUsageString() + "\n"; -3670 } else if (extName == "subjectKeyIdentifier") { -3671 s += " " + this.getExtSubjectKeyIdentifier().kid.hex + "\n"; -3672 } else if (extName == "authorityKeyIdentifier") { -3673 var akid = this.getExtAuthorityKeyIdentifier(); -3674 if (akid.kid !== undefined) -3675 s += " kid=" + akid.kid.hex + "\n"; -3676 } else if (extName == "extKeyUsage") { -3677 var eku = this.getExtExtKeyUsage().array; -3678 s += " " + eku.join(", ") + "\n"; -3679 } else if (extName == "subjectAltName") { -3680 var san = _getSubjectAltNameStr(this.getExtSubjectAltName()); -3681 s += san + "\n"; -3682 } else if (extName == "cRLDistributionPoints") { -3683 var cdp = this.getExtCRLDistributionPoints(); -3684 s += _getCRLDistributionPointsStr(cdp); -3685 } else if (extName == "authorityInfoAccess") { -3686 var aia = this.getExtAuthorityInfoAccess(); -3687 s += _getAuthorityInfoAccessStr(aia); -3688 } else if (extName == "certificatePolicies") { -3689 s += _getCertificatePoliciesStr(this.getExtCertificatePolicies()); -3690 } -3691 } -3692 } -3693 -3694 s += "signature algorithm: " + this.getSignatureAlgorithmName() + "\n"; -3695 s += "signature: " + this.getSignatureValueHex().substr(0, 16) + "...\n"; -3696 return s; -3697 }; -3698 -3699 if (typeof params == "string") { -3700 if (params.indexOf("-----BEGIN") != -1) { -3701 this.readCertPEM(params); -3702 } else if (KJUR.lang.String.isHex(params)) { -3703 this.readCertHex(params); -3704 } -3705 } -3706 }; -3707 // ----- END of X509 class ----- -3708 -3709 /** -3710 * additional definition for X.509 extension parsers<br/> -3711 * @see X509.registExtParser -3712 */ -3713 X509.EXT_PARSER = { -3714 }; -3715 -3716 /** -3717 * define X.509 extension parser for specified OID<br/> -3718 * @name registExtParser -3719 * @memberOf X509 -3720 * @function -3721 * @param {string} oid extension OID string (ex. "1.2.3.4") -3722 * @param {function} func registering func extension value parsing function -3723 * @return unspecified -3724 * @since jsrsasign 10.7.0 x509 2.1.2 -3725 * -3726 * @description -3727 * <p> -3728 * This static method specifies a X.509 extension value parsing function -3729 * for specified an extension OID. -3730 * </p> -3731 * <p> -3732 * Extension parser function must have following three arguments: -3733 * <ul> -3734 * <li>{string} oid - OID for extension (ex. "1.2.3.4")</li> -3735 * <li>{boolean} critical - critical flag of extension</li> -3736 * <li>{string} hExtV - hexadecimal string of extension value</li> -3737 * </ul> -3738 * The funcition must return an associative array for the extension -3739 * when hExtV can be parsed properly. Otherwise it must return -3740 * value "undefined". -3741 * </p> -3742 * -3743 * @example -3744 * function _extparser1(oid, critical, hExtV) { -3745 * try { -3746 * var result = { extname: oid, value: ASN1HEX.parse(hExtV).utf8str.str }; -3747 * if (critical) result.critical = true; -3748 * return result; -3749 * } catch(ex) { -3750 * return undefined; -3751 * } -3752 * } -3753 * X509.registExtParser("1.2.3.4", _extparser1); -3754 */ -3755 X509.registExtParser = function(oid, func) { -3756 X509.EXT_PARSER[oid] = func; -3757 }; -3758 -3759 /** -3760 * get distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER X.500 name<br/> -3761 * @name hex2dn -3762 * @memberOf X509 -3763 * @function -3764 * @param {String} hex hexadecimal string of ASN.1 DER distinguished name -3765 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) -3766 * @return {String} OpenSSL online format distinguished name -3767 * @description -3768 * This static method converts from a hexadecimal string of -3769 * distinguished name (DN) -3770 * specified by 'hex' and 'idx' to OpenSSL oneline string representation (ex. /C=US/O=a). -3771 * @example -3772 * X509.hex2dn("3031310b3...") → /C=US/O=a/CN=b2+OU=b1 -3773 */ -3774 X509.hex2dn = function(hex, idx) { -3775 if (idx === undefined) idx = 0; -3776 var x = new X509(); -3777 var hDN = ASN1HEX.getTLV(hex, idx); -3778 var pDN = x.getX500Name(hex); -3779 return pDN.str; -3780 }; -3781 -3782 /** -3783 * get relative distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER RDN<br/> -3784 * @name hex2rdn -3785 * @memberOf X509 -3786 * @function -3787 * @param {String} hex hexadecimal string of ASN.1 DER concludes relative distinguished name -3788 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) -3789 * @return {String} OpenSSL online format relative distinguished name -3790 * @description -3791 * This static method converts from a hexadecimal string of -3792 * relative distinguished name (RDN) -3793 * specified by 'hex' and 'idx' to LDAP string representation (ex. O=test+CN=test).<br/> -3794 * NOTE: Multi-valued RDN is supported since jsnrsasign 6.2.2 x509 1.1.10. -3795 * @example -3796 * X509.hex2rdn("310a3008060355040a0c0161") → O=a -3797 * X509.hex2rdn("31143008060355040a0c01613008060355040a0c0162") → O=a+O=b -3798 */ -3799 X509.hex2rdn = function(hex, idx) { -3800 if (idx === undefined) idx = 0; -3801 if (hex.substr(idx, 2) !== "31") throw new Error("malformed RDN"); -3802 -3803 var a = new Array(); -3804 -3805 var aIdx = ASN1HEX.getChildIdx(hex, idx); -3806 for (var i = 0; i < aIdx.length; i++) { -3807 a.push(X509.hex2attrTypeValue(hex, aIdx[i])); -3808 } -3809 -3810 a = a.map(function(s) { return s.replace("+", "\\+"); }); -3811 return a.join("+"); -3812 }; -3813 -3814 /** -3815 * get string from hexadecimal string of ASN.1 DER AttributeTypeAndValue<br/> -3816 * @name hex2attrTypeValue -3817 * @memberOf X509 -3818 * @function -3819 * @param {String} hex hexadecimal string of ASN.1 DER concludes AttributeTypeAndValue -3820 * @param {Integer} idx index of hexadecimal string (DEFAULT=0) -3821 * @return {String} string representation of AttributeTypeAndValue (ex. C=US) -3822 * @description -3823 * This static method converts from a hexadecimal string of AttributeTypeAndValue -3824 * specified by 'hex' and 'idx' to LDAP string representation (ex. C=US). -3825 * @example -3826 * X509.hex2attrTypeValue("3008060355040a0c0161") → O=a -3827 * X509.hex2attrTypeValue("300806035504060c0161") → C=a -3828 * X509.hex2attrTypeValue("...3008060355040a0c0161...", 128) → O=a -3829 */ -3830 X509.hex2attrTypeValue = function(hex, idx) { -3831 var _ASN1HEX = ASN1HEX; -3832 var _getV = _ASN1HEX.getV; -3833 -3834 if (idx === undefined) idx = 0; -3835 if (hex.substr(idx, 2) !== "30") -3836 throw new Error("malformed attribute type and value"); -3837 -3838 var aIdx = _ASN1HEX.getChildIdx(hex, idx); -3839 if (aIdx.length !== 2 || hex.substr(aIdx[0], 2) !== "06") -3840 "malformed attribute type and value"; -3841 -3842 var oidHex = _getV(hex, aIdx[0]); -3843 var oidInt = KJUR.asn1.ASN1Util.oidHexToInt(oidHex); -3844 var atype = KJUR.asn1.x509.OID.oid2atype(oidInt); -3845 -3846 var hV = _getV(hex, aIdx[1]); -3847 var rawV = hextorstr(hV); -3848 -3849 return atype + "=" + rawV; -3850 }; -3851 -3852 /** -3853 * get RSA/DSA/ECDSA public key object from X.509 certificate hexadecimal string<br/> -3854 * @name getPublicKeyFromCertHex -3855 * @memberOf X509 -3856 * @function -3857 * @param {String} h hexadecimal string of X.509 certificate for RSA/ECDSA/DSA public key -3858 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key -3859 * @since jsrasign 7.1.0 x509 1.1.11 -3860 */ -3861 X509.getPublicKeyFromCertHex = function(h) { -3862 var x = new X509(); -3863 x.readCertHex(h); -3864 return x.getPublicKey(); -3865 }; -3866 -3867 /** -3868 * get RSA/DSA/ECDSA public key object from PEM certificate string -3869 * @name getPublicKeyFromCertPEM -3870 * @memberOf X509 -3871 * @function -3872 * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate -3873 * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key -3874 * @since x509 1.1.1 -3875 * @description -3876 * NOTE: DSA is also supported since x509 1.1.2. -3877 */ -3878 X509.getPublicKeyFromCertPEM = function(sCertPEM) { -3879 var x = new X509(); -3880 x.readCertPEM(sCertPEM); -3881 return x.getPublicKey(); -3882 }; -3883 -3884 /** -3885 * get public key information from PEM certificate -3886 * @name getPublicKeyInfoPropOfCertPEM -3887 * @memberOf X509 -3888 * @function -3889 * @param {String} sCertPEM string of PEM formatted certificate -3890 * @return {Hash} hash of information for public key -3891 * @since x509 1.1.1 -3892 * @description -3893 * Resulted associative array has following properties:<br/> -3894 * <ul> -3895 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li> -3896 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li> -3897 * <li>keyhex - hexadecimal string of key in the certificate</li> -3898 * </ul> -3899 * NOTE: X509v1 certificate is also supported since x509.js 1.1.9. -3900 */ -3901 X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) { -3902 var _ASN1HEX = ASN1HEX; -3903 var _getVbyList = _ASN1HEX.getVbyList; -3904 -3905 var result = {}; -3906 var x, hSPKI, pubkey; -3907 result.algparam = null; -3908 -3909 x = new X509(); -3910 x.readCertPEM(sCertPEM); -3911 -3912 hSPKI = x.getPublicKeyHex(); -3913 result.keyhex = _getVbyList(hSPKI, 0, [1], "03").substr(2); -3914 result.algoid = _getVbyList(hSPKI, 0, [0, 0], "06"); -3915 -3916 if (result.algoid === "2a8648ce3d0201") { // ecPublicKey -3917 result.algparam = _getVbyList(hSPKI, 0, [0, 1], "06"); -3918 }; -3919 -3920 return result; -3921 }; -3922 -3923 /* ====================================================================== -3924 * Specific V3 Extensions -3925 * ====================================================================== */ -3926 -3927 X509.KEYUSAGE_NAME = [ -3928 "digitalSignature", -3929 "nonRepudiation", -3930 "keyEncipherment", -3931 "dataEncipherment", -3932 "keyAgreement", -3933 "keyCertSign", -3934 "cRLSign", -3935 "encipherOnly", -3936 "decipherOnly" -3937 ]; -3938