# frozen_string_literal: true require "cose/key/curve" require "cose/key/curve_key" require "openssl" module COSE module Key class OKP < CurveKey KTY_OKP = 1 def self.enforce_type(map) if map[LABEL_KTY] != KTY_OKP raise "Not an OKP key" end end def self.from_pkey(pkey) curve = Curve.by_pkey_name(pkey.oid) || raise("Unsupported edwards curve #{pkey.oid}") attributes = { crv: curve.id } asymmetric_key = pkey.public_to_der public_key_bit_string = OpenSSL::ASN1.decode(asymmetric_key).value.last.value attributes[:x] = public_key_bit_string begin asymmetric_key = pkey.private_to_der private_key = OpenSSL::ASN1.decode(asymmetric_key).value.last.value curve_private_key = OpenSSL::ASN1.decode(private_key).value attributes[:d] = curve_private_key rescue OpenSSL::PKey::PKeyError # work around lack of https://github.com/ruby/openssl/pull/527, otherwise raises this error # with message 'i2d_PKCS8PrivateKey_bio: error converting private key' for public keys nil end new(**attributes) end def map super.merge(LABEL_KTY => KTY_OKP) end def to_pkey if curve private_key_algo = OpenSSL::ASN1::Sequence.new( [OpenSSL::ASN1::ObjectId.new(curve.pkey_name)] ) seq = if d version = OpenSSL::ASN1::Integer.new(0) curve_private_key = OpenSSL::ASN1::OctetString.new(d).to_der private_key = OpenSSL::ASN1::OctetString.new(curve_private_key) [version, private_key_algo, private_key] else public_key = OpenSSL::ASN1::BitString.new(x) [private_key_algo, public_key] end asymmetric_key = OpenSSL::ASN1::Sequence.new(seq) OpenSSL::PKey.read(asymmetric_key.to_der) else raise "Unsupported curve #{crv}" end end def curve Curve.find(crv) end end end end