cert-to-cwt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/cert-to-cwt.rb +193 -0
  3. data/cert-to-cwt.gemspec +19 -0
  4. 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
@@ -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
@@ -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: []