|
4 | 4 |
|
5 | 5 | module JWT |
6 | 6 | module JWK |
7 | | - class EC < KeyBase |
| 7 | + class EC < KeyBase # rubocop:disable Metrics/ClassLength |
8 | 8 | extend Forwardable |
9 | 9 | def_delegators :keypair, :public_key |
10 | 10 |
|
@@ -121,31 +121,69 @@ def jwk_attrs(jwk_data, attrs) |
121 | 121 | end |
122 | 122 | end |
123 | 123 |
|
124 | | - def ec_pkey(jwk_crv, jwk_x, jwk_y, jwk_d) |
125 | | - curve = to_openssl_curve(jwk_crv) |
126 | | - |
127 | | - x_octets = decode_octets(jwk_x) |
128 | | - y_octets = decode_octets(jwk_y) |
129 | | - |
130 | | - key = OpenSSL::PKey::EC.new(curve) |
131 | | - |
132 | | - # The details of the `Point` instantiation are covered in: |
133 | | - # - https://docs.ruby-lang.org/en/2.4.0/OpenSSL/PKey/EC.html |
134 | | - # - https://www.openssl.org/docs/manmaster/man3/EC_POINT_new.html |
135 | | - # - https://tools.ietf.org/html/rfc5480#section-2.2 |
136 | | - # - https://www.secg.org/SEC1-Ver-1.0.pdf |
137 | | - # Section 2.3.3 of the last of these references specifies that the |
138 | | - # encoding of an uncompressed point consists of the byte `0x04` followed |
139 | | - # by the x value then the y value. |
140 | | - point = OpenSSL::PKey::EC::Point.new( |
141 | | - OpenSSL::PKey::EC::Group.new(curve), |
142 | | - OpenSSL::BN.new([0x04, x_octets, y_octets].pack('Ca*a*'), 2) |
143 | | - ) |
144 | | - |
145 | | - key.public_key = point |
146 | | - key.private_key = OpenSSL::BN.new(decode_octets(jwk_d), 2) if jwk_d |
147 | | - |
148 | | - key |
| 124 | + if ::JWT.openssl_3? |
| 125 | + def ec_pkey(jwk_crv, jwk_x, jwk_y, jwk_d) # rubocop:disable Metrics/MethodLength |
| 126 | + curve = to_openssl_curve(jwk_crv) |
| 127 | + |
| 128 | + x_octets = decode_octets(jwk_x) |
| 129 | + y_octets = decode_octets(jwk_y) |
| 130 | + |
| 131 | + point = OpenSSL::PKey::EC::Point.new( |
| 132 | + OpenSSL::PKey::EC::Group.new(curve), |
| 133 | + OpenSSL::BN.new([0x04, x_octets, y_octets].pack('Ca*a*'), 2) |
| 134 | + ) |
| 135 | + |
| 136 | + sequence = if jwk_d |
| 137 | + # https://datatracker.ietf.org/doc/html/rfc5915.html |
| 138 | + # ECPrivateKey ::= SEQUENCE { |
| 139 | + # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), |
| 140 | + # privateKey OCTET STRING, |
| 141 | + # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, |
| 142 | + # publicKey [1] BIT STRING OPTIONAL |
| 143 | + # } |
| 144 | + |
| 145 | + OpenSSL::ASN1::Sequence([ |
| 146 | + OpenSSL::ASN1::Integer(1), |
| 147 | + OpenSSL::ASN1::OctetString(OpenSSL::BN.new(decode_octets(jwk_d), 2).to_s(2)), |
| 148 | + OpenSSL::ASN1::ObjectId(curve, 0, :EXPLICIT), |
| 149 | + OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT) |
| 150 | + ]) |
| 151 | + else |
| 152 | + OpenSSL::ASN1::Sequence([ |
| 153 | + OpenSSL::ASN1::Sequence([OpenSSL::ASN1::ObjectId('id-ecPublicKey'), OpenSSL::ASN1::ObjectId(curve)]), |
| 154 | + OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed)) |
| 155 | + ]) |
| 156 | + end |
| 157 | + |
| 158 | + OpenSSL::PKey::EC.new(sequence.to_der) |
| 159 | + end |
| 160 | + else |
| 161 | + def ec_pkey(jwk_crv, jwk_x, jwk_y, jwk_d) |
| 162 | + curve = to_openssl_curve(jwk_crv) |
| 163 | + |
| 164 | + x_octets = decode_octets(jwk_x) |
| 165 | + y_octets = decode_octets(jwk_y) |
| 166 | + |
| 167 | + key = OpenSSL::PKey::EC.new(curve) |
| 168 | + |
| 169 | + # The details of the `Point` instantiation are covered in: |
| 170 | + # - https://docs.ruby-lang.org/en/2.4.0/OpenSSL/PKey/EC.html |
| 171 | + # - https://www.openssl.org/docs/manmaster/man3/EC_POINT_new.html |
| 172 | + # - https://tools.ietf.org/html/rfc5480#section-2.2 |
| 173 | + # - https://www.secg.org/SEC1-Ver-1.0.pdf |
| 174 | + # Section 2.3.3 of the last of these references specifies that the |
| 175 | + # encoding of an uncompressed point consists of the byte `0x04` followed |
| 176 | + # by the x value then the y value. |
| 177 | + point = OpenSSL::PKey::EC::Point.new( |
| 178 | + OpenSSL::PKey::EC::Group.new(curve), |
| 179 | + OpenSSL::BN.new([0x04, x_octets, y_octets].pack('Ca*a*'), 2) |
| 180 | + ) |
| 181 | + |
| 182 | + key.public_key = point |
| 183 | + key.private_key = OpenSSL::BN.new(decode_octets(jwk_d), 2) if jwk_d |
| 184 | + |
| 185 | + key |
| 186 | + end |
149 | 187 | end |
150 | 188 |
|
151 | 189 | def decode_octets(jwk_data) |
|
0 commit comments