cose 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3065ed49e2bb4795f22f0fe132fd1645f7db6062ce7102cf6fde7aeb23859657
4
- data.tar.gz: c4dc7b4bab6fd4c2898be067c60ca52b43ca743ee8b1dae5359a1a659a0f8d2c
3
+ metadata.gz: 8a7da6d20b462494510800b95be262f6100a46b0b066c8255de6f1250a41429b
4
+ data.tar.gz: a758caf5a05445bc36b4c8e2e64f562c181546eb9740d065e48d2c3c5ea22726
5
5
  SHA512:
6
- metadata.gz: ce3922d45c7dfca8cc649e89e775169ade6bc2ea7d5fdad829380452c7337c79989b33c198105fc134e36719bc147324678638c0e5235fd4a5776412c2e9d07f
7
- data.tar.gz: ae49b8afa26ee2bf25f90f3052f9cd9cf20f68c12b2541859b80c524e9b0d8a9d9b433dd82f247ade6b2430bff852eb67c83724ee60edf61676b0505096a393d
6
+ metadata.gz: 47e4e46bb5e633a1e0eccb8fc9081411d1ff09439046f8ead15070aa2a2f3329d3b34e9744aa56a13a1cb0e6ff0490abc3148efe8e87d5d9efcaeb0f86fa514b
7
+ data.tar.gz: 2bc529d8091353b0a90a7b04b8e33d490371bfc87c43149a977cde769234b69e9645d9ca8c5677088a91faef8630806c24435ad304551fe467dba4d0cd421971
@@ -25,8 +25,12 @@ jobs:
25
25
  - openssl_3_0
26
26
  - openssl_2_2
27
27
  - openssl_2_1
28
- - openssl_2_0
29
28
  - openssl_default
29
+ exclude:
30
+ - ruby: '2.4.10'
31
+ gemfile: openssl_3_0
32
+ - ruby: '2.5.8'
33
+ gemfile: openssl_3_0
30
34
  env:
31
35
  BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
32
36
  steps:
data/Appraisals CHANGED
@@ -8,10 +8,6 @@ appraise "openssl_2_1" do
8
8
  gem "openssl", "~> 2.1.0"
9
9
  end
10
10
 
11
- appraise "openssl_2_0" do
12
- gem "openssl", "~> 2.0.0"
13
- end
14
-
15
11
  appraise "openssl_3_0" do
16
12
  gem "openssl", "~> 3.0.0"
17
13
  end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.3.0] - 2022-10-28
4
+
5
+ - Add support for EdDSA (#55). Credits to @bdewater.
6
+
3
7
  ## [v1.2.1] - 2022-07-03
4
8
 
5
9
  - Support OpenSSL ~>3.0.0. Credits to @ClearlyClaire <3
@@ -139,7 +143,8 @@ NOTE: No breaking changes. Moving out of `v0.x` to express the intention to keep
139
143
  - EC2 key object
140
144
  - Works with ruby 2.5
141
145
 
142
- [v1.2.0]: https://github.com/cedarcode/cose-ruby/compare/v1.2.0...v1.2.1/
146
+ [v1.3.0]: https://github.com/cedarcode/cose-ruby/compare/v1.2.1...v1.3.0/
147
+ [v1.2.1]: https://github.com/cedarcode/cose-ruby/compare/v1.2.0...v1.2.1/
143
148
  [v1.2.0]: https://github.com/cedarcode/cose-ruby/compare/v1.1.0...v1.2.0/
144
149
  [v1.1.0]: https://github.com/cedarcode/cose-ruby/compare/v1.0.0...v1.1.0/
145
150
  [v1.0.0]: https://github.com/cedarcode/cose-ruby/compare/v0.11.0...v1.0.0/
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "openssl", "~> 2.0.0"
5
+ gem "openssl", "~> 3.0.0"
6
6
 
7
7
  gemspec path: "../"
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cose/algorithm/signature_algorithm"
4
+ require "cose/error"
5
+ require "cose/key/okp"
6
+ require "openssl"
7
+
8
+ module COSE
9
+ module Algorithm
10
+ class EdDSA < SignatureAlgorithm
11
+ private
12
+
13
+ def valid_key?(key)
14
+ cose_key = to_cose_key(key)
15
+
16
+ cose_key.is_a?(COSE::Key::OKP) && (!cose_key.alg || cose_key.alg == id)
17
+ end
18
+
19
+ def to_pkey(key)
20
+ case key
21
+ when COSE::Key::OKP
22
+ key.to_pkey
23
+ when OpenSSL::PKey::PKey
24
+ key
25
+ else
26
+ raise(COSE::Error, "Incompatible key for algorithm")
27
+ end
28
+ end
29
+
30
+ def valid_signature?(key, signature, verification_data)
31
+ pkey = to_pkey(key)
32
+
33
+ begin
34
+ pkey.verify(nil, signature, verification_data)
35
+ rescue OpenSSL::PKey::PKeyError
36
+ false
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "cose/algorithm/ecdsa"
4
+ require "cose/algorithm/eddsa"
4
5
  require "cose/algorithm/hmac"
5
6
  require "cose/algorithm/rsa_pss"
6
7
 
@@ -30,6 +31,7 @@ module COSE
30
31
  register(ECDSA.new(-35, "ES384", hash_function: "SHA384", curve_name: "P-384"))
31
32
  register(ECDSA.new(-36, "ES512", hash_function: "SHA512", curve_name: "P-521"))
32
33
  register(ECDSA.new(-47, "ES256K", hash_function: "SHA256", curve_name: "secp256k1"))
34
+ register(EdDSA.new(-8, "EdDSA"))
33
35
  register(RSAPSS.new(-37, "PS256", hash_function: "SHA256", salt_length: 32))
34
36
  register(RSAPSS.new(-38, "PS384", hash_function: "SHA384", salt_length: 48))
35
37
  register(RSAPSS.new(-39, "PS512", hash_function: "SHA512", salt_length: 64))
@@ -32,4 +32,6 @@ end
32
32
  COSE::Key::Curve.register(1, "P-256", "prime256v1")
33
33
  COSE::Key::Curve.register(2, "P-384", "secp384r1")
34
34
  COSE::Key::Curve.register(3, "P-521", "secp521r1")
35
+ COSE::Key::Curve.register(6, "Ed25519", "ED25519")
36
+ COSE::Key::Curve.register(7, "Ed448", "ED448")
35
37
  COSE::Key::Curve.register(8, "secp256k1", "secp256k1")
data/lib/cose/key/ec2.rb CHANGED
@@ -68,28 +68,33 @@ module COSE
68
68
  def to_pkey
69
69
  if curve
70
70
  group = OpenSSL::PKey::EC::Group.new(curve.pkey_name)
71
- pkey = OpenSSL::PKey::EC.new(group)
72
71
  public_key_bn = OpenSSL::BN.new("\x04" + x + y, 2)
73
72
  public_key_point = OpenSSL::PKey::EC::Point.new(group, public_key_bn)
74
73
 
75
74
  # RFC5480 SubjectPublicKeyInfo
76
- asn1 = OpenSSL::ASN1::Sequence([
77
- OpenSSL::ASN1::Sequence([
78
- OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
79
- OpenSSL::ASN1::ObjectId(curve.pkey_name),
80
- ]),
81
- OpenSSL::ASN1::BitString(public_key_point.to_octet_string(:uncompressed))
82
- ])
75
+ asn1 = OpenSSL::ASN1::Sequence(
76
+ [
77
+ OpenSSL::ASN1::Sequence(
78
+ [
79
+ OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
80
+ OpenSSL::ASN1::ObjectId(curve.pkey_name),
81
+ ]
82
+ ),
83
+ OpenSSL::ASN1::BitString(public_key_point.to_octet_string(:uncompressed))
84
+ ]
85
+ )
83
86
 
84
87
  if d
85
88
  # RFC5915 ECPrivateKey
86
- asn1 = OpenSSL::ASN1::Sequence([
87
- OpenSSL::ASN1::Integer.new(1),
88
- # Not properly padded but OpenSSL doesn't mind
89
- OpenSSL::ASN1::OctetString(OpenSSL::BN.new(d, 2).to_s(2)),
90
- OpenSSL::ASN1::ObjectId(curve.pkey_name, 0, :EXPLICIT),
91
- OpenSSL::ASN1::BitString(public_key_point.to_octet_string(:uncompressed), 1, :EXPLICIT),
92
- ])
89
+ asn1 = OpenSSL::ASN1::Sequence(
90
+ [
91
+ OpenSSL::ASN1::Integer.new(1),
92
+ # Not properly padded but OpenSSL doesn't mind
93
+ OpenSSL::ASN1::OctetString(OpenSSL::BN.new(d, 2).to_s(2)),
94
+ OpenSSL::ASN1::ObjectId(curve.pkey_name, 0, :EXPLICIT),
95
+ OpenSSL::ASN1::BitString(public_key_point.to_octet_string(:uncompressed), 1, :EXPLICIT),
96
+ ]
97
+ )
93
98
 
94
99
  der = asn1.to_der
95
100
  return OpenSSL::PKey::EC.new(der)
data/lib/cose/key/okp.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cose/key/curve"
3
4
  require "cose/key/curve_key"
4
5
  require "openssl"
5
6
 
@@ -14,9 +15,56 @@ module COSE
14
15
  end
15
16
  end
16
17
 
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
+
17
39
  def map
18
40
  super.merge(LABEL_KTY => KTY_OKP)
19
41
  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
20
68
  end
21
69
  end
22
70
  end
data/lib/cose/key/rsa.rb CHANGED
@@ -89,25 +89,29 @@ module COSE
89
89
 
90
90
  def to_pkey
91
91
  # PKCS#1 RSAPublicKey
92
- asn1 = OpenSSL::ASN1::Sequence([
93
- OpenSSL::ASN1::Integer.new(bn(n)),
94
- OpenSSL::ASN1::Integer.new(bn(e)),
95
- ])
92
+ asn1 = OpenSSL::ASN1::Sequence(
93
+ [
94
+ OpenSSL::ASN1::Integer.new(bn(n)),
95
+ OpenSSL::ASN1::Integer.new(bn(e)),
96
+ ]
97
+ )
96
98
  pkey = OpenSSL::PKey::RSA.new(asn1.to_der)
97
99
 
98
100
  if private?
99
101
  # PKCS#1 RSAPrivateKey
100
- asn1 = OpenSSL::ASN1::Sequence([
101
- OpenSSL::ASN1::Integer.new(0),
102
- OpenSSL::ASN1::Integer.new(bn(n)),
103
- OpenSSL::ASN1::Integer.new(bn(e)),
104
- OpenSSL::ASN1::Integer.new(bn(d)),
105
- OpenSSL::ASN1::Integer.new(bn(p)),
106
- OpenSSL::ASN1::Integer.new(bn(q)),
107
- OpenSSL::ASN1::Integer.new(bn(dp)),
108
- OpenSSL::ASN1::Integer.new(bn(dq)),
109
- OpenSSL::ASN1::Integer.new(bn(qinv)),
110
- ])
102
+ asn1 = OpenSSL::ASN1::Sequence(
103
+ [
104
+ OpenSSL::ASN1::Integer.new(0),
105
+ OpenSSL::ASN1::Integer.new(bn(n)),
106
+ OpenSSL::ASN1::Integer.new(bn(e)),
107
+ OpenSSL::ASN1::Integer.new(bn(d)),
108
+ OpenSSL::ASN1::Integer.new(bn(p)),
109
+ OpenSSL::ASN1::Integer.new(bn(q)),
110
+ OpenSSL::ASN1::Integer.new(bn(dp)),
111
+ OpenSSL::ASN1::Integer.new(bn(dq)),
112
+ OpenSSL::ASN1::Integer.new(bn(qinv)),
113
+ ]
114
+ )
111
115
 
112
116
  pkey = OpenSSL::PKey::RSA.new(asn1.to_der)
113
117
  end
data/lib/cose/key.rb CHANGED
@@ -24,6 +24,8 @@ module COSE
24
24
  COSE::Key::EC2.from_pkey(pkey)
25
25
  when OpenSSL::PKey::RSA
26
26
  COSE::Key::RSA.from_pkey(pkey)
27
+ when OpenSSL::PKey::PKey
28
+ COSE::Key::OKP.from_pkey(pkey)
27
29
  else
28
30
  raise "Unsupported #{pkey.class} object"
29
31
  end
data/lib/cose/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module COSE
4
- VERSION = "1.2.1"
4
+ VERSION = "1.3.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cose
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gonzalo Rodriguez
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-07-03 00:00:00.000000000 Z
12
+ date: 2022-10-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cbor
@@ -166,14 +166,15 @@ files:
166
166
  - bin/console
167
167
  - bin/setup
168
168
  - cose.gemspec
169
- - gemfiles/openssl_2_0.gemfile
170
169
  - gemfiles/openssl_2_1.gemfile
171
170
  - gemfiles/openssl_2_2.gemfile
171
+ - gemfiles/openssl_3_0.gemfile
172
172
  - gemfiles/openssl_default.gemfile
173
173
  - lib/cose.rb
174
174
  - lib/cose/algorithm.rb
175
175
  - lib/cose/algorithm/base.rb
176
176
  - lib/cose/algorithm/ecdsa.rb
177
+ - lib/cose/algorithm/eddsa.rb
177
178
  - lib/cose/algorithm/hmac.rb
178
179
  - lib/cose/algorithm/rsa_pss.rb
179
180
  - lib/cose/algorithm/signature_algorithm.rb