cose 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +8 -2
- data/Appraisals +7 -0
- data/CHANGELOG.md +10 -0
- data/README.md +59 -18
- data/cose.gemspec +1 -0
- data/gemfiles/openssl_2_0.gemfile +7 -0
- data/gemfiles/openssl_2_1.gemfile +7 -0
- data/lib/cose/key.rb +12 -0
- data/lib/cose/key/ec2.rb +67 -0
- data/lib/cose/key/rsa.rb +85 -2
- data/lib/cose/version.rb +1 -1
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb978af65e0e7ba43a06e776b45792856bec76e58a7ce6d1d3d88619c6fca09e
|
4
|
+
data.tar.gz: c8cdf73b87523e266c36076c542cf91bb5e252bda826523308b4adc355ce1c6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc8f10f840915de994963318cf3fb5f138eb836bd391280029cceb7b5b4c9a95577dd281be1d67f1dc36def4a5a809af6e4ff665dc26e0cf30990219248cf043
|
7
|
+
data.tar.gz: 87ec47c8278246a0fdbec217a1d13b6588aed62400bfd49010d4573dab75b70a436867fe8d4fb895b784bbe29783c28e2910f576f213aeda8d830662f1067f7f
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
|
+
|
3
4
|
rvm:
|
4
5
|
- ruby-head
|
5
|
-
- 2.6.
|
6
|
-
- 2.5.
|
6
|
+
- 2.6.2
|
7
|
+
- 2.5.4
|
7
8
|
- 2.4.5
|
9
|
+
|
10
|
+
gemfile:
|
11
|
+
- gemfiles/openssl_2_0.gemfile
|
12
|
+
- gemfiles/openssl_2_1.gemfile
|
13
|
+
|
8
14
|
before_install: gem install bundler -v 2.0.1
|
9
15
|
|
10
16
|
matrix:
|
data/Appraisals
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v0.5.0] - 2019-03-25
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- `COSE::Key.serialize(openssl_pkey)` serializes an `OpenSSL::PKey::PKey` object into CBOR data. Supports RSA keys plus
|
8
|
+
EC keys from curves prime256v1, secp384r1 and secp521r1.
|
9
|
+
- `COSE::Key::EC2#to_pkey` converts to an `OpenSSL::PKey::EC` object
|
10
|
+
- `COSE::Key::RSA#to_pkey` converts to an `OpenSSL::PKey::RSA` object
|
11
|
+
|
3
12
|
## [v0.4.1] - 2019-03-12
|
4
13
|
|
5
14
|
### Fixed
|
@@ -45,6 +54,7 @@
|
|
45
54
|
- EC2 key object
|
46
55
|
- Works with ruby 2.5
|
47
56
|
|
57
|
+
[v0.5.0]: https://github.com/cedarcode/cose-ruby/compare/v0.4.1...v0.5.0/
|
48
58
|
[v0.4.1]: https://github.com/cedarcode/cose-ruby/compare/v0.4.0...v0.4.1/
|
49
59
|
[v0.4.0]: https://github.com/cedarcode/cose-ruby/compare/v0.3.0...v0.4.0/
|
50
60
|
[v0.3.0]: https://github.com/cedarcode/cose-ruby/compare/v0.2.0...v0.3.0/
|
data/README.md
CHANGED
@@ -25,12 +25,23 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
### Key Objects
|
27
27
|
|
28
|
+
#### Deserialization (from CBOR to Ruby objects)
|
29
|
+
|
28
30
|
```ruby
|
29
31
|
cbor_data = "..."
|
30
32
|
|
31
|
-
|
33
|
+
cose_key = COSE::Key.deserialize(cbor_data)
|
34
|
+
```
|
35
|
+
|
36
|
+
Once you have a `COSE::Key` instance you can either access key parameters directly and/or convert it to an
|
37
|
+
`OpenSSL::PKey::PKey` instance for operating with it (encrypting/decrypting, signing/verifying, etc).
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
# Convert to an OpenSSL::PKey::PKey
|
41
|
+
openssl_pkey = cose_key.to_pkey
|
32
42
|
|
33
|
-
|
43
|
+
# Access COSE key parameters
|
44
|
+
case key
|
34
45
|
when COSE::Key::EC2
|
35
46
|
key.curve
|
36
47
|
key.x_coordinate
|
@@ -39,43 +50,73 @@ when COSE::Key::EC2
|
|
39
50
|
when COSE::Key::RSA
|
40
51
|
key.modulus_n
|
41
52
|
key.public_exponent_e
|
53
|
+
key.private_exponent_d
|
54
|
+
key.prime_factor_p
|
55
|
+
key.prime_factor_q
|
56
|
+
key.d_p
|
57
|
+
key.d_q
|
58
|
+
key.q_inv
|
42
59
|
when COSE::Key::Symmetric
|
43
60
|
key.key_value
|
44
61
|
end
|
45
62
|
```
|
46
63
|
|
47
|
-
|
64
|
+
If you already know which COSE key type is encoded in the CBOR data, then:
|
48
65
|
|
49
66
|
```ruby
|
50
|
-
|
67
|
+
ec2_key_cbor = "..."
|
68
|
+
|
69
|
+
cose_ec2_key = COSE::Key::EC2.deserialize(ec2_key_cbor)
|
70
|
+
|
71
|
+
cose_ec2_key.curve
|
72
|
+
cose_ec2_key.x_coordinate
|
73
|
+
cose_ec2_key.y_coordinate
|
74
|
+
cose_ec2_key.d_coordinate
|
51
75
|
|
52
|
-
|
76
|
+
# or
|
53
77
|
|
54
|
-
|
55
|
-
key.x_coordinate
|
56
|
-
key.y_coordinate
|
57
|
-
key.d_coordinate
|
78
|
+
ec_pkey = cose_ec2_key.to_pkey # Instance of an OpenSSL::PKey::EC
|
58
79
|
```
|
59
80
|
|
60
|
-
|
81
|
+
```ruby
|
82
|
+
symmetric_key_cbor = "..."
|
83
|
+
|
84
|
+
cose_symmetric_key = COSE::Key::Symmetric.deserialize(symmetric_key_cbor)
|
85
|
+
|
86
|
+
cose_symmetric_key.key_value
|
87
|
+
```
|
61
88
|
|
62
89
|
```ruby
|
63
|
-
|
90
|
+
rsa_key_cbor = "..."
|
91
|
+
|
92
|
+
cose_rsa_key = COSE::Key::RSA.deserialize(rsa_key_cbor)
|
93
|
+
|
94
|
+
cose_rsa_key.modulus_n
|
95
|
+
cose_rsa_key.public_exponent_e
|
96
|
+
cose_rsa_key.private_exponent_d
|
97
|
+
cose_rsa_key.prime_factor_p
|
98
|
+
cose_rsa_key.prime_factor_q
|
99
|
+
cose_rsa_key.d_p
|
100
|
+
cose_rsa_key.d_q
|
101
|
+
cose_rsa_key.q_inv
|
64
102
|
|
65
|
-
|
103
|
+
# or
|
66
104
|
|
67
|
-
|
105
|
+
rsa_pkey = cose_rsa_key.to_pkey # Instance of an OpenSSL::PKey::RSA
|
68
106
|
```
|
69
107
|
|
70
|
-
####
|
108
|
+
#### Serialization (from Ruby objects to CBOR)
|
71
109
|
|
72
110
|
```ruby
|
73
|
-
|
111
|
+
ec_pkey = OpenSSL::PKey::EC.new("prime256v1").generate_key
|
112
|
+
|
113
|
+
cose_ec2_key_cbor = COSE::Key.serialize(ec_pkey)
|
114
|
+
```
|
74
115
|
|
75
|
-
|
116
|
+
```ruby
|
117
|
+
rsa_pkey = OpenSSL::PKey::RSA.new(2048)
|
76
118
|
|
77
|
-
|
78
|
-
key.public_exponent_e
|
119
|
+
cose_rsa_key_cbor = COSE::Key.serialize(rsa_pkey)
|
79
120
|
```
|
80
121
|
|
81
122
|
### Signing Objects
|
data/cose.gemspec
CHANGED
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
|
34
34
|
spec.add_dependency "cbor", "~> 0.5.9.2"
|
35
35
|
|
36
|
+
spec.add_development_dependency "appraisal", "~> 2.2.0"
|
36
37
|
spec.add_development_dependency "bundler", ">= 1.17", "< 3"
|
37
38
|
spec.add_development_dependency "byebug", "~> 11.0"
|
38
39
|
spec.add_development_dependency "rake", "~> 12.3"
|
data/lib/cose/key.rb
CHANGED
@@ -2,11 +2,23 @@ require "cbor"
|
|
2
2
|
require "cose/key/ec2"
|
3
3
|
require "cose/key/rsa"
|
4
4
|
require "cose/key/symmetric"
|
5
|
+
require "openssl"
|
5
6
|
|
6
7
|
module COSE
|
7
8
|
class UnknownKeyType < StandardError; end
|
8
9
|
|
9
10
|
module Key
|
11
|
+
def self.serialize(pkey)
|
12
|
+
case pkey
|
13
|
+
when OpenSSL::PKey::EC, OpenSSL::PKey::EC::Point
|
14
|
+
COSE::Key::EC2.from_pkey(pkey).serialize
|
15
|
+
when OpenSSL::PKey::RSA
|
16
|
+
COSE::Key::RSA.from_pkey(pkey).serialize
|
17
|
+
else
|
18
|
+
raise "Unsupported serialization of #{pkey.class} object"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
10
22
|
def self.deserialize(data)
|
11
23
|
map = CBOR.decode(data)
|
12
24
|
|
data/lib/cose/key/ec2.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "cose/key/base"
|
4
|
+
require "openssl"
|
4
5
|
|
5
6
|
module COSE
|
6
7
|
module Key
|
@@ -13,6 +14,44 @@ module COSE
|
|
13
14
|
Y_LABEL = -3
|
14
15
|
|
15
16
|
KTY_EC2 = 2
|
17
|
+
CRV_P256 = 1
|
18
|
+
CRV_P384 = 2
|
19
|
+
CRV_P521 = 3
|
20
|
+
|
21
|
+
PKEY_CURVES = {
|
22
|
+
CRV_P256 => "prime256v1",
|
23
|
+
CRV_P384 => "secp384r1",
|
24
|
+
CRV_P521 => "secp521r1"
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
def self.from_pkey(pkey)
|
28
|
+
curve = PKEY_CURVES.key(pkey.group.curve_name) || raise("Unsupported EC curve #{pkey.group.curve_name}")
|
29
|
+
|
30
|
+
case pkey
|
31
|
+
when OpenSSL::PKey::EC::Point
|
32
|
+
public_key = pkey
|
33
|
+
when OpenSSL::PKey::EC
|
34
|
+
public_key = pkey.public_key
|
35
|
+
private_key = pkey.private_key
|
36
|
+
else
|
37
|
+
raise "Unsupported"
|
38
|
+
end
|
39
|
+
|
40
|
+
if public_key
|
41
|
+
bytes = public_key.to_bn.to_s(2)[1..-1]
|
42
|
+
|
43
|
+
coordinate_length = bytes.size / 2
|
44
|
+
|
45
|
+
x_coordinate = bytes[0..(coordinate_length - 1)]
|
46
|
+
y_coordinate = bytes[coordinate_length..-1]
|
47
|
+
end
|
48
|
+
|
49
|
+
if private_key
|
50
|
+
d_coordinate = private_key.to_s(2)
|
51
|
+
end
|
52
|
+
|
53
|
+
new(curve: curve, x_coordinate: x_coordinate, y_coordinate: y_coordinate, d_coordinate: d_coordinate)
|
54
|
+
end
|
16
55
|
|
17
56
|
attr_reader :algorithm, :curve, :d_coordinate, :x_coordinate, :y_coordinate
|
18
57
|
|
@@ -32,6 +71,34 @@ module COSE
|
|
32
71
|
end
|
33
72
|
end
|
34
73
|
|
74
|
+
def serialize
|
75
|
+
CBOR.encode(
|
76
|
+
Base::LABEL_KTY => KTY_EC2,
|
77
|
+
CRV_LABEL => curve,
|
78
|
+
X_LABEL => x_coordinate,
|
79
|
+
Y_LABEL => y_coordinate,
|
80
|
+
D_LABEL => d_coordinate
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_pkey
|
85
|
+
if PKEY_CURVES[curve]
|
86
|
+
group = OpenSSL::PKey::EC::Group.new(PKEY_CURVES[curve])
|
87
|
+
pkey = OpenSSL::PKey::EC.new(group)
|
88
|
+
public_key_bn = OpenSSL::BN.new("\x04" + x_coordinate + y_coordinate, 2)
|
89
|
+
public_key_point = OpenSSL::PKey::EC::Point.new(group, public_key_bn)
|
90
|
+
pkey.public_key = public_key_point
|
91
|
+
|
92
|
+
if d_coordinate
|
93
|
+
pkey.private_key = OpenSSL::BN.new(d_coordinate, 2)
|
94
|
+
end
|
95
|
+
|
96
|
+
pkey
|
97
|
+
else
|
98
|
+
raise "Unsupported curve #{curve}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
35
102
|
def self.from_map(map)
|
36
103
|
enforce_type(map, KTY_EC2, "Not an EC2 key")
|
37
104
|
|
data/lib/cose/key/rsa.rb
CHANGED
@@ -1,18 +1,65 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "cose/key/base"
|
4
|
+
require "openssl"
|
4
5
|
|
5
6
|
module COSE
|
6
7
|
module Key
|
7
8
|
class RSA < Base
|
8
9
|
LABEL_N = -1
|
9
10
|
LABEL_E = -2
|
11
|
+
LABEL_D = -3
|
12
|
+
LABEL_P = -4
|
13
|
+
LABEL_Q = -5
|
14
|
+
LABEL_D_P = -6
|
15
|
+
LABEL_D_Q = -7
|
16
|
+
LABEL_Q_INV = -8
|
10
17
|
|
11
18
|
KTY_RSA = 3
|
12
19
|
|
13
|
-
|
20
|
+
def self.from_pkey(pkey)
|
21
|
+
params = pkey.params
|
14
22
|
|
15
|
-
|
23
|
+
attributes = {
|
24
|
+
modulus_n: params["n"].to_s(2),
|
25
|
+
public_exponent_e: params["e"].to_s(2)
|
26
|
+
}
|
27
|
+
|
28
|
+
if pkey.private?
|
29
|
+
attributes.merge!(
|
30
|
+
private_exponent_d: params["d"].to_s(2),
|
31
|
+
prime_factor_p: params["p"].to_s(2),
|
32
|
+
prime_factor_q: params["q"].to_s(2),
|
33
|
+
d_p: params["dmp1"].to_s(2),
|
34
|
+
d_q: params["dmq1"].to_s(2),
|
35
|
+
q_inv: params["iqmp"].to_s(2)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
new(attributes)
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader(
|
43
|
+
:modulus_n,
|
44
|
+
:public_exponent_e,
|
45
|
+
:private_exponent_d,
|
46
|
+
:prime_factor_p,
|
47
|
+
:prime_factor_q,
|
48
|
+
:d_p,
|
49
|
+
:d_q,
|
50
|
+
:q_inv
|
51
|
+
)
|
52
|
+
|
53
|
+
def initialize(
|
54
|
+
modulus_n:,
|
55
|
+
public_exponent_e:,
|
56
|
+
private_exponent_d: nil,
|
57
|
+
prime_factor_p: nil,
|
58
|
+
prime_factor_q: nil,
|
59
|
+
d_p: nil,
|
60
|
+
d_q: nil,
|
61
|
+
q_inv: nil
|
62
|
+
)
|
16
63
|
if !modulus_n
|
17
64
|
raise ArgumentError, "Required modulus_n is missing"
|
18
65
|
elsif !public_exponent_e
|
@@ -20,14 +67,50 @@ module COSE
|
|
20
67
|
else
|
21
68
|
@modulus_n = modulus_n
|
22
69
|
@public_exponent_e = public_exponent_e
|
70
|
+
@private_exponent_d = private_exponent_d
|
71
|
+
@prime_factor_p = prime_factor_p
|
72
|
+
@prime_factor_q = prime_factor_q
|
73
|
+
@d_p = d_p
|
74
|
+
@d_q = d_q
|
75
|
+
@q_inv = q_inv
|
23
76
|
end
|
24
77
|
end
|
25
78
|
|
79
|
+
def serialize
|
80
|
+
CBOR.encode(
|
81
|
+
Base::LABEL_KTY => KTY_RSA,
|
82
|
+
LABEL_N => modulus_n,
|
83
|
+
LABEL_E => public_exponent_e,
|
84
|
+
LABEL_D => private_exponent_d,
|
85
|
+
LABEL_P => prime_factor_p,
|
86
|
+
LABEL_Q => prime_factor_q,
|
87
|
+
LABEL_D_P => d_p,
|
88
|
+
LABEL_D_Q => d_q,
|
89
|
+
LABEL_Q_INV => q_inv
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_pkey
|
94
|
+
pkey = OpenSSL::PKey::RSA.new
|
95
|
+
|
96
|
+
pkey.set_key(bn(modulus_n), bn(public_exponent_e), bn(private_exponent_d))
|
97
|
+
pkey.set_factors(bn(prime_factor_p), bn(prime_factor_q))
|
98
|
+
pkey.set_crt_params(bn(d_p), bn(d_q), bn(q_inv))
|
99
|
+
|
100
|
+
pkey
|
101
|
+
end
|
102
|
+
|
26
103
|
def self.from_map(map)
|
27
104
|
enforce_type(map, KTY_RSA, "Not an RSA key")
|
28
105
|
|
29
106
|
new(modulus_n: map[LABEL_N], public_exponent_e: map[LABEL_E])
|
30
107
|
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def bn(data)
|
112
|
+
OpenSSL::BN.new(data, 2)
|
113
|
+
end
|
31
114
|
end
|
32
115
|
end
|
33
116
|
end
|
data/lib/cose/version.rb
CHANGED
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: 0.
|
4
|
+
version: 0.5.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: 2019-03-
|
12
|
+
date: 2019-03-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cbor
|
@@ -25,6 +25,20 @@ dependencies:
|
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 0.5.9.2
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: appraisal
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 2.2.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.2.0
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: bundler
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -113,6 +127,7 @@ files:
|
|
113
127
|
- ".rspec"
|
114
128
|
- ".rubocop.yml"
|
115
129
|
- ".travis.yml"
|
130
|
+
- Appraisals
|
116
131
|
- CHANGELOG.md
|
117
132
|
- Gemfile
|
118
133
|
- LICENSE.txt
|
@@ -121,6 +136,8 @@ files:
|
|
121
136
|
- bin/console
|
122
137
|
- bin/setup
|
123
138
|
- cose.gemspec
|
139
|
+
- gemfiles/openssl_2_0.gemfile
|
140
|
+
- gemfiles/openssl_2_1.gemfile
|
124
141
|
- lib/cose.rb
|
125
142
|
- lib/cose/encrypt.rb
|
126
143
|
- lib/cose/encrypt0.rb
|