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