cose 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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