lib/cose/key/okp.rb in cose-1.2.1 vs lib/cose/key/okp.rb in cose-1.3.0

- old
+ new

@@ -1,7 +1,8 @@ # frozen_string_literal: true +require "cose/key/curve" require "cose/key/curve_key" require "openssl" module COSE module Key @@ -12,11 +13,58 @@ 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