11# frozen_string_literal: true
22
3+ require "cose/key/curve"
34require "cose/key/curve_key"
45require "openssl"
56
@@ -14,9 +15,56 @@ def self.enforce_type(map)
1415 end
1516 end
1617
18+ def self . from_pkey ( pkey )
19+ curve = Curve . by_pkey_name ( pkey . oid ) || raise ( "Unsupported edwards curve #{ pkey . oid } " )
20+ attributes = { crv : curve . id }
21+
22+ asymmetric_key = pkey . public_to_der
23+ public_key_bit_string = OpenSSL ::ASN1 . decode ( asymmetric_key ) . value . last . value
24+ attributes [ :x ] = public_key_bit_string
25+ begin
26+ asymmetric_key = pkey . private_to_der
27+ private_key = OpenSSL ::ASN1 . decode ( asymmetric_key ) . value . last . value
28+ curve_private_key = OpenSSL ::ASN1 . decode ( private_key ) . value
29+ attributes [ :d ] = curve_private_key
30+ rescue OpenSSL ::PKey ::PKeyError
31+ # work around lack of https://github.com/ruby/openssl/pull/527, otherwise raises this error
32+ # with message 'i2d_PKCS8PrivateKey_bio: error converting private key' for public keys
33+ nil
34+ end
35+
36+ new ( **attributes )
37+ end
38+
1739 def map
1840 super . merge ( LABEL_KTY => KTY_OKP )
1941 end
42+
43+ def to_pkey
44+ if curve
45+ private_key_algo = OpenSSL ::ASN1 ::Sequence . new (
46+ [ OpenSSL ::ASN1 ::ObjectId . new ( curve . pkey_name ) ]
47+ )
48+ seq = if d
49+ version = OpenSSL ::ASN1 ::Integer . new ( 0 )
50+ curve_private_key = OpenSSL ::ASN1 ::OctetString . new ( d ) . to_der
51+ private_key = OpenSSL ::ASN1 ::OctetString . new ( curve_private_key )
52+ [ version , private_key_algo , private_key ]
53+ else
54+ public_key = OpenSSL ::ASN1 ::BitString . new ( x )
55+ [ private_key_algo , public_key ]
56+ end
57+
58+ asymmetric_key = OpenSSL ::ASN1 ::Sequence . new ( seq )
59+ OpenSSL ::PKey . read ( asymmetric_key . to_der )
60+ else
61+ raise "Unsupported curve #{ crv } "
62+ end
63+ end
64+
65+ def curve
66+ Curve . find ( crv )
67+ end
2068 end
2169 end
2270end
0 commit comments