1+ <?php 
2+ 
3+ namespace  Firebase \JWT ;
4+ 
5+ class  ECPublicKey
6+ {
7+     const  ASN1_INTEGER  = 0x02 ;
8+     const  ASN1_BIT_STRING  = 0x03 ;
9+     const  ASN1_OBJECT_IDENTIFIER  = 0x06 ;
10+     const  ASN1_SEQUENCE  = 0x10 ;
11+     const  OID  = '1.2.840.10045.2.1 ' ;
12+ 
13+     private  $ data
14+ 
15+     private  static  $ curves
16+         'P-256 '  => '1.2.840.10045.3.1.7 ' , // Len: 64 
17+         // 'P-384' => '1.3.132.0.34', // Len: 96 (not yet supported) 
18+         // 'P-521' => '1.3.132.0.35', // Len: 132 (not supported) 
19+     ];
20+ 
21+     public  function  __construct (array  $ data
22+     {
23+         if  (isset ($ data'd ' ])) {
24+             // The key is actually a private key 
25+             throw  new  \Exception ('Key data must be for a public key ' );
26+         }
27+ 
28+         if  (empty ($ data'crv ' ])) {
29+             throw  new  \Exception ('crv not set ' );
30+         }
31+ 
32+         if  (!isset (self ::$ curves$ data'crv ' ]])) {
33+             throw  new  \Exception ('Unrecognised or unsupported EC curve ' );
34+         }
35+ 
36+         $ this data  = $ data
37+     }
38+ 
39+     public  function  toPEM ()
40+     {
41+         $ oidself ::$ curves$ this data ['crv ' ]];
42+         $ pem
43+             self ::encodeDER (
44+                 self ::ASN1_SEQUENCE ,
45+                 self ::encodeDER (
46+                     self ::ASN1_SEQUENCE ,
47+                     self ::encodeDER (
48+                         self ::ASN1_OBJECT_IDENTIFIER ,
49+                         self ::encodeOID (self ::OID )
50+                     )
51+                     . self ::encodeDER (
52+                         self ::ASN1_OBJECT_IDENTIFIER ,
53+                         self ::encodeOID ($ oid
54+                     )
55+                 ) .
56+                 self ::encodeDER (
57+                     self ::ASN1_BIT_STRING ,
58+                     chr (0x00 ) . chr (0x04 )
59+                     . JWT ::urlsafeB64Decode ($ this data ['x ' ])
60+                     . JWT ::urlsafeB64Decode ($ this data ['y ' ])
61+                 )
62+             );
63+ 
64+         return  sprintf (
65+             "-----BEGIN PUBLIC KEY----- \n%s \n-----END PUBLIC KEY----- \n" ,
66+             wordwrap (base64_encode ($ pem64 , "\n" , true )
67+         );
68+     }
69+ 
70+     /** 
71+      * Convert an ECDSA signature to an ASN.1 DER sequence 
72+      * 
73+      * @param   string $sig The ECDSA signature to convert 
74+      * @return  string The encoded DER object 
75+      */ 
76+     public  static  function  encodeSignature ($ sig
77+     {
78+         // Separate the signature into r-value and s-value 
79+         list ($ r$ sstr_split ($ sigint ) (strlen ($ sig2 ));
80+ 
81+         // Trim leading zeros 
82+         $ rltrim ($ r"\x00" );
83+         $ sltrim ($ s"\x00" );
84+ 
85+         // Convert r-value and s-value from unsigned big-endian integers to 
86+         // signed two's complement 
87+         if  (ord ($ r0 ]) > 0x7f ) {
88+             $ r"\x00"  . $ r
89+         }
90+         if  (ord ($ s0 ]) > 0x7f ) {
91+             $ s"\x00"  . $ s
92+         }
93+ 
94+         return  self ::encodeDER (
95+             self ::ASN1_SEQUENCE ,
96+             self ::encodeDER (self ::ASN1_INTEGER , $ r
97+             self ::encodeDER (self ::ASN1_INTEGER , $ s
98+         );
99+     }
100+ 
101+     /** 
102+      * Encodes a value into a DER object. 
103+      * 
104+      * @param   int     $type DER tag 
105+      * @param   string  $value the value to encode 
106+      * @return  string  the encoded object 
107+      */ 
108+     private  static  function  encodeDER ($ type$ value
109+     {
110+         $ tag_header0 ;
111+         if  ($ typeself ::ASN1_SEQUENCE ) {
112+             $ tag_header0x20 ;
113+         }
114+ 
115+         // Type 
116+         $ derchr ($ tag_header$ type
117+ 
118+         // Length 
119+         $ derchr (strlen ($ value
120+ 
121+         return  $ der$ value
122+     }
123+ 
124+     /** 
125+      * Encodes a string into a DER-encoded OID. 
126+      * 
127+      * @param   string $oid the OID string 
128+      * @return  string the binary DER-encoded OID 
129+      */ 
130+     private  static  function  encodeOID ($ oid
131+     {
132+         $ octetsexplode ('. ' , $ oid
133+ 
134+         // Get the first octet 
135+         $ oidchr (array_shift ($ octets40  + array_shift ($ octets
136+ 
137+         // Iterate over subsequent octets 
138+         foreach  ($ octetsas  $ octet
139+             if  ($ octet0 ) {
140+                 $ oidchr (0x00 );
141+                 continue ;
142+             }
143+             $ bin'' ;
144+ 
145+             while  ($ octet
146+                 $ binchr (0x80  | ($ octet0x7f ));
147+                 $ octet7 ;
148+             }
149+             $ bin0 ] = $ bin0 ] & chr (0x7f );
150+ 
151+             // Convert to big endian if necessary 
152+             if  (pack ('V ' , 65534 ) == pack ('L ' , 65534 )) {
153+                 $ oidstrrev ($ bin
154+             } else  {
155+                 $ oid$ bin
156+             }
157+         }
158+ 
159+         return  $ oid
160+     }
161+ }
0 commit comments