cert-to-cwt 0.0.1
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 +7 -0
- data/bin/cert-to-cwt.rb +193 -0
- data/cert-to-cwt.gemspec +19 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3f30a9c6e0631d3daaca07bac5a27a9dc34bd4cb
|
4
|
+
data.tar.gz: e78ff0859be82052447ac491c072d78b5f217919
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9ff25fea72d4b4ae22172b72ccf3f739d2607d221ac855a498a24dabb00f2f8900cd7b8f33a49217a102ddb091b781f9f93c8d25d83e6600372059729f432a86
|
7
|
+
data.tar.gz: e1626c35abfbca01ad4d00157ce149add3330414ac5dee2ce532d6ed65709a3244f15f6814df534ad0fd18e23f08252887dba1da1df6f262e3a89b7c94b71f87
|
data/bin/cert-to-cwt.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'asn1-pure.rb'
|
2
|
+
require 'yaml'
|
3
|
+
require 'time'
|
4
|
+
require 'cbor-diagnostic'
|
5
|
+
|
6
|
+
class String
|
7
|
+
def hexi
|
8
|
+
bytes.map{|x| "%02x" % x}.join
|
9
|
+
end
|
10
|
+
def hexs
|
11
|
+
bytes.map{|x| "%02x" % x}.join(" ")
|
12
|
+
end
|
13
|
+
def xeh
|
14
|
+
gsub(/\s/, "").chars.each_slice(2).map{ |x| Integer(x.join, 16).chr("BINARY") }.join
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if ARGV[0] == "-b"
|
19
|
+
ARGV.shift
|
20
|
+
$binary = true
|
21
|
+
end
|
22
|
+
DUMPFILE = "dumped-cert.yml"
|
23
|
+
if ARGV[0] == "-d"
|
24
|
+
ARGV.shift
|
25
|
+
$dump = true
|
26
|
+
end
|
27
|
+
if ARGV[0] == "-b"
|
28
|
+
ARGV.shift
|
29
|
+
$binary = true
|
30
|
+
end
|
31
|
+
f = ARGF.read.b
|
32
|
+
|
33
|
+
def numbertobytes(n) # doesn't work for 0
|
34
|
+
if n == 0
|
35
|
+
"".b
|
36
|
+
else
|
37
|
+
s = n.to_s(16)
|
38
|
+
s[0...0] = "0" if s.size.odd?
|
39
|
+
[s].pack("H*").b
|
40
|
+
end
|
41
|
+
end
|
42
|
+
fail unless numbertobytes(0) == ""
|
43
|
+
fail unless numbertobytes(10) == "\x0A"
|
44
|
+
fail unless numbertobytes(160) == "\xA0".b
|
45
|
+
fail unless numbertobytes(1000) == "\x03\xE8".b
|
46
|
+
|
47
|
+
def bitstringtobytes(s)
|
48
|
+
fail "bitstring #{s}" if s[0] != "\0"
|
49
|
+
s[1..-1]
|
50
|
+
end
|
51
|
+
|
52
|
+
def datetimeasn1(s)
|
53
|
+
Time.iso8601(s.sub(/\A(..)(..)(..)(..)(..)(..)Z\z/){"20#$1-#$2-#$3T#$4:#$5:#$6Z"}).to_i
|
54
|
+
end
|
55
|
+
|
56
|
+
OIDLOOKUP = Hash.new {|h, k| k}
|
57
|
+
%w(
|
58
|
+
2.5.4.3 CN
|
59
|
+
1.2.840.113549.1.9.1 E
|
60
|
+
2.5.4.11 OU
|
61
|
+
2.5.4.10 O
|
62
|
+
2.5.4.7 L
|
63
|
+
2.5.4.8 ST
|
64
|
+
2.5.4.6 C
|
65
|
+
0.9.2342.19200300.100.1.25 DC
|
66
|
+
|
67
|
+
2.5.4.12 TITLE
|
68
|
+
0.9.2342.19200300.100.1.3 MAIL
|
69
|
+
2.5.4.5 SERIALNUMBER
|
70
|
+
1.2.840.113549.1.9.2 UNSTRUCTUREDNAME
|
71
|
+
1.2.840.113549.1.9.8 UNSTRUCTUREDADDRESS
|
72
|
+
2.5.4.42 GN
|
73
|
+
2.5.4.4 SN
|
74
|
+
|
75
|
+
2.5.4.9 STREET
|
76
|
+
0.9.2342.19200300.100.1.1 UID
|
77
|
+
).each_slice(2).map{ |x, y| OIDLOOKUP[x] = y}
|
78
|
+
# middle group stolen from netscape certificate management system administrator guide
|
79
|
+
# puts OIDLOOKUP.to_yaml
|
80
|
+
|
81
|
+
def dntostring(dn) # almost RFC 4514
|
82
|
+
sets = dn.fetch(:seq)
|
83
|
+
sets.map do |s|
|
84
|
+
g = s.fetch(:set)
|
85
|
+
g.map do |elt|
|
86
|
+
aname, aval = elt.fetch(:seq)
|
87
|
+
[OIDLOOKUP[aname], aval.values.first.gsub(/[ #"+,;<>\\]/){"\\#$&"}].join("=")
|
88
|
+
end.join("+")
|
89
|
+
end.join(",")
|
90
|
+
end
|
91
|
+
|
92
|
+
ALGLOOKUP = Hash.new {|h, k| k}
|
93
|
+
%w(
|
94
|
+
1.2.840.113549.1.1.11 sha256WithRSAEncryption
|
95
|
+
1.2.840.113549.1.1.1 rsaEncryption
|
96
|
+
).each_slice(2).map{ |x, y| ALGLOOKUP[x] = y.intern}
|
97
|
+
|
98
|
+
SYMLOOKUP = Hash.new {|h, k| warn "label unknown for key :#{k}"; k}
|
99
|
+
%w(
|
100
|
+
iss 1
|
101
|
+
sub 2
|
102
|
+
aud 3
|
103
|
+
exp 4
|
104
|
+
nbf 5
|
105
|
+
iat 6
|
106
|
+
cti 7
|
107
|
+
|
108
|
+
|
109
|
+
kty 1
|
110
|
+
n -1
|
111
|
+
e -2
|
112
|
+
|
113
|
+
serial -100000
|
114
|
+
pk -100001
|
115
|
+
).each_slice(2).map{ |x, y| SYMLOOKUP[x.intern] = y.to_i}
|
116
|
+
|
117
|
+
def desymbolicate(o)
|
118
|
+
case o
|
119
|
+
when Symbol
|
120
|
+
SYMLOOKUP[o]
|
121
|
+
when Hash
|
122
|
+
Hash[o.map {|k, v| [desymbolicate(k), desymbolicate(v)]}]
|
123
|
+
when Array
|
124
|
+
o.map {|x| desymbolicate(x)}
|
125
|
+
else
|
126
|
+
o
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# RFC 4514
|
131
|
+
|
132
|
+
cert = ASN1.decode(f)
|
133
|
+
claimset = {}
|
134
|
+
if $dump
|
135
|
+
warn "Dumping cert as #{DUMPFILE}..."
|
136
|
+
File.write(DUMPFILE, cert.to_yaml)
|
137
|
+
end
|
138
|
+
tbs, sigalg, sigval = cert.fetch(:seq)
|
139
|
+
ver, ser, sigalg1, iss, validity, sub, spki, *rest = tbs.fetch(:seq)
|
140
|
+
fail [:ver, ver].inspect unless ver == {exp0: [2]}
|
141
|
+
fail [:ser, set].inspect unless Integer === ser
|
142
|
+
claimset[:serial] = ser
|
143
|
+
fail [:alg, sigalg, sigalg1].inspect unless sigalg == sigalg1
|
144
|
+
|
145
|
+
decoded_sigalg = ALGLOOKUP[sigalg.fetch(:seq).first]
|
146
|
+
# p decoded_sigalg
|
147
|
+
|
148
|
+
notbefore, notafter = validity.fetch(:seq).map{|x| datetimeasn1(x.fetch(:t))}
|
149
|
+
# p [notbefore, notafter]
|
150
|
+
claimset[:nbf] = notbefore
|
151
|
+
claimset[:exp] = notafter
|
152
|
+
|
153
|
+
claimset[:iss] = dntostring(iss)
|
154
|
+
claimset[:sub] = dntostring(sub)
|
155
|
+
|
156
|
+
pkalg, pkbits = spki.fetch(:seq)
|
157
|
+
decoded_pkalg = ALGLOOKUP[pkalg.fetch(:seq).first]
|
158
|
+
kk = bitstringtobytes(pkbits.fetch(:bits))
|
159
|
+
case decoded_pkalg
|
160
|
+
when :rsaEncryption
|
161
|
+
kk = ASN1.decode(kk)
|
162
|
+
n, e = kk.fetch(:seq)
|
163
|
+
u = CBOR.encode(n)
|
164
|
+
claimset[:pk] = {kty: 3, n: numbertobytes(n), e: numbertobytes(e)}
|
165
|
+
else
|
166
|
+
claimset[:pk] = [decoded_pkalg, kk] # TODO convert to COSE key
|
167
|
+
end
|
168
|
+
|
169
|
+
rest1 = rest.reduce({}, :merge)
|
170
|
+
|
171
|
+
exp3 = rest1.delete(:exp3)
|
172
|
+
puts [:rest1, rest1].to_yaml unless rest1 == {}
|
173
|
+
|
174
|
+
exp3[0].fetch(:seq).each do |e3|
|
175
|
+
name, crit, val = e3.fetch(:seq)
|
176
|
+
if Hash === crit
|
177
|
+
val = crit
|
178
|
+
crit = false
|
179
|
+
end
|
180
|
+
val = val.fetch(:b)
|
181
|
+
# val = ASN1.decode(val)
|
182
|
+
claimset[name] = val # er, ignoring crit right now
|
183
|
+
end
|
184
|
+
|
185
|
+
claimset = desymbolicate(claimset)
|
186
|
+
|
187
|
+
claimset_cbor = claimset.to_cbor
|
188
|
+
warn "CBOR size: #{claimset_cbor.size}"
|
189
|
+
if $binary
|
190
|
+
print claimset_cbor
|
191
|
+
else
|
192
|
+
puts CBOR.decode(claimset_cbor).cbor_diagnostic
|
193
|
+
end
|
data/cert-to-cwt.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "cert-to-cwt"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.summary = "Convert an X.509 cert into a CWT claim set"
|
5
|
+
s.description = %q{cert-to-cwt is a highly experimental converter for X.509 certificates into CWT claim sets.}
|
6
|
+
s.author = "Carsten Bormann"
|
7
|
+
s.email = "cabo@tzi.org"
|
8
|
+
s.license = "Apache-2.0"
|
9
|
+
s.has_rdoc = false
|
10
|
+
s.files = Dir['lib/**/*.rb'] + %w(cert-to-cwt.gemspec) + Dir['bin/**/*.rb']
|
11
|
+
s.executables = Dir['bin/**/*.rb'].map {|x| File.basename(x)}
|
12
|
+
s.required_ruby_version = '>= 2.4.1'
|
13
|
+
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
|
16
|
+
s.add_development_dependency 'bundler', '~>1'
|
17
|
+
s.add_dependency 'cbor-diag'
|
18
|
+
s.add_dependency 'asn1-diag'
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cert-to-cwt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Carsten Bormann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-08-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: cbor-diag
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: asn1-diag
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: cert-to-cwt is a highly experimental converter for X.509 certificates
|
56
|
+
into CWT claim sets.
|
57
|
+
email: cabo@tzi.org
|
58
|
+
executables:
|
59
|
+
- cert-to-cwt.rb
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- bin/cert-to-cwt.rb
|
64
|
+
- cert-to-cwt.gemspec
|
65
|
+
homepage:
|
66
|
+
licenses:
|
67
|
+
- Apache-2.0
|
68
|
+
metadata: {}
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.4.1
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 2.6.11
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: Convert an X.509 cert into a CWT claim set
|
89
|
+
test_files: []
|