lib/cose/key/ec2.rb in cose-0.4.1 vs lib/cose/key/ec2.rb in cose-0.5.0

- old
+ new

@@ -1,8 +1,9 @@ # frozen_string_literal: true require "cose/key/base" +require "openssl" module COSE module Key class EC2 < Base ALG_LABEL = 3 @@ -11,11 +12,49 @@ D_LABEL = -4 X_LABEL = -2 Y_LABEL = -3 KTY_EC2 = 2 + CRV_P256 = 1 + CRV_P384 = 2 + CRV_P521 = 3 + PKEY_CURVES = { + CRV_P256 => "prime256v1", + CRV_P384 => "secp384r1", + CRV_P521 => "secp521r1" + }.freeze + + def self.from_pkey(pkey) + curve = PKEY_CURVES.key(pkey.group.curve_name) || raise("Unsupported EC curve #{pkey.group.curve_name}") + + case pkey + when OpenSSL::PKey::EC::Point + public_key = pkey + when OpenSSL::PKey::EC + public_key = pkey.public_key + private_key = pkey.private_key + else + raise "Unsupported" + end + + if public_key + bytes = public_key.to_bn.to_s(2)[1..-1] + + coordinate_length = bytes.size / 2 + + x_coordinate = bytes[0..(coordinate_length - 1)] + y_coordinate = bytes[coordinate_length..-1] + end + + if private_key + d_coordinate = private_key.to_s(2) + end + + new(curve: curve, x_coordinate: x_coordinate, y_coordinate: y_coordinate, d_coordinate: d_coordinate) + end + attr_reader :algorithm, :curve, :d_coordinate, :x_coordinate, :y_coordinate def initialize(algorithm: nil, curve:, d_coordinate: nil, x_coordinate:, y_coordinate:) if !curve raise ArgumentError, "Required curve is missing" @@ -27,9 +66,37 @@ @algorithm = algorithm @curve = curve @d_coordinate = d_coordinate @x_coordinate = x_coordinate @y_coordinate = y_coordinate + end + end + + def serialize + CBOR.encode( + Base::LABEL_KTY => KTY_EC2, + CRV_LABEL => curve, + X_LABEL => x_coordinate, + Y_LABEL => y_coordinate, + D_LABEL => d_coordinate + ) + end + + def to_pkey + if PKEY_CURVES[curve] + group = OpenSSL::PKey::EC::Group.new(PKEY_CURVES[curve]) + pkey = OpenSSL::PKey::EC.new(group) + public_key_bn = OpenSSL::BN.new("\x04" + x_coordinate + y_coordinate, 2) + public_key_point = OpenSSL::PKey::EC::Point.new(group, public_key_bn) + pkey.public_key = public_key_point + + if d_coordinate + pkey.private_key = OpenSSL::BN.new(d_coordinate, 2) + end + + pkey + else + raise "Unsupported curve #{curve}" end end def self.from_map(map) enforce_type(map, KTY_EC2, "Not an EC2 key")