1 | =begin
|
---|
2 | = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses
|
---|
3 |
|
---|
4 | = Info
|
---|
5 | 'OpenSSL for Ruby 2' project
|
---|
6 | Copyright (C) 2002 Michal Rokos <[email protected]>
|
---|
7 | All rights reserved.
|
---|
8 |
|
---|
9 | = Licence
|
---|
10 | This program is licenced under the same licence as Ruby.
|
---|
11 | (See the file 'LICENCE'.)
|
---|
12 |
|
---|
13 | = Version
|
---|
14 | $Id: x509.rb 11708 2007-02-12 23:01:19Z shyouhei $
|
---|
15 | =end
|
---|
16 |
|
---|
17 | require "openssl"
|
---|
18 |
|
---|
19 | module OpenSSL
|
---|
20 | module X509
|
---|
21 | class ExtensionFactory
|
---|
22 | def create_extension(*arg)
|
---|
23 | if arg.size > 1
|
---|
24 | create_ext(*arg)
|
---|
25 | else
|
---|
26 | send("create_ext_from_"+arg[0].class.name.downcase, arg[0])
|
---|
27 | end
|
---|
28 | end
|
---|
29 |
|
---|
30 | def create_ext_from_array(ary)
|
---|
31 | raise ExtensionError, "unexpected array form" if ary.size > 3
|
---|
32 | create_ext(ary[0], ary[1], ary[2])
|
---|
33 | end
|
---|
34 |
|
---|
35 | def create_ext_from_string(str) # "oid = critical, value"
|
---|
36 | oid, value = str.split(/=/, 2)
|
---|
37 | oid.strip!
|
---|
38 | value.strip!
|
---|
39 | create_ext(oid, value)
|
---|
40 | end
|
---|
41 |
|
---|
42 | def create_ext_from_hash(hash)
|
---|
43 | create_ext(hash["oid"], hash["value"], hash["critical"])
|
---|
44 | end
|
---|
45 | end
|
---|
46 |
|
---|
47 | class Extension
|
---|
48 | def to_s # "oid = critical, value"
|
---|
49 | str = self.oid
|
---|
50 | str << " = "
|
---|
51 | str << "critical, " if self.critical?
|
---|
52 | str << self.value.gsub(/\n/, ", ")
|
---|
53 | end
|
---|
54 |
|
---|
55 | def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
|
---|
56 | {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?}
|
---|
57 | end
|
---|
58 |
|
---|
59 | def to_a
|
---|
60 | [ self.oid, self.value, self.critical? ]
|
---|
61 | end
|
---|
62 | end
|
---|
63 |
|
---|
64 | class Name
|
---|
65 | module RFC2253DN
|
---|
66 | Special = ',=+<>#;'
|
---|
67 | HexChar = /[0-9a-fA-F]/
|
---|
68 | HexPair = /#{HexChar}#{HexChar}/
|
---|
69 | HexString = /#{HexPair}+/
|
---|
70 | Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/
|
---|
71 | StringChar = /[^#{Special}\\"]/
|
---|
72 | QuoteChar = /[^\\"]/
|
---|
73 | AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/
|
---|
74 | AttributeValue = /
|
---|
75 | (?!["#])((?:#{StringChar}|#{Pair})*)|
|
---|
76 | \#(#{HexString})|
|
---|
77 | "((?:#{QuoteChar}|#{Pair})*)"
|
---|
78 | /x
|
---|
79 | TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/
|
---|
80 |
|
---|
81 | module_function
|
---|
82 |
|
---|
83 | def expand_pair(str)
|
---|
84 | return nil unless str
|
---|
85 | return str.gsub(Pair){|pair|
|
---|
86 | case pair.size
|
---|
87 | when 2 then pair[1,1]
|
---|
88 | when 3 then Integer("0x#{pair[1,2]}").chr
|
---|
89 | else raise OpenSSL::X509::NameError, "invalid pair: #{str}"
|
---|
90 | end
|
---|
91 | }
|
---|
92 | end
|
---|
93 |
|
---|
94 | def expand_hexstring(str)
|
---|
95 | return nil unless str
|
---|
96 | der = str.gsub(HexPair){|hex| Integer("0x#{hex}").chr }
|
---|
97 | a1 = OpenSSL::ASN1.decode(der)
|
---|
98 | return a1.value, a1.tag
|
---|
99 | end
|
---|
100 |
|
---|
101 | def expand_value(str1, str2, str3)
|
---|
102 | value = expand_pair(str1)
|
---|
103 | value, tag = expand_hexstring(str2) unless value
|
---|
104 | value = expand_pair(str3) unless value
|
---|
105 | return value, tag
|
---|
106 | end
|
---|
107 |
|
---|
108 | def scan(dn)
|
---|
109 | str = dn
|
---|
110 | ary = []
|
---|
111 | while true
|
---|
112 | if md = TypeAndValue.match(str)
|
---|
113 | matched = md.to_s
|
---|
114 | remain = md.post_match
|
---|
115 | type = md[1]
|
---|
116 | value, tag = expand_value(md[2], md[3], md[4]) rescue nil
|
---|
117 | if value
|
---|
118 | type_and_value = [type, value]
|
---|
119 | type_and_value.push(tag) if tag
|
---|
120 | ary.unshift(type_and_value)
|
---|
121 | if remain.length > 2 && remain[0] == ?,
|
---|
122 | str = remain[1..-1]
|
---|
123 | next
|
---|
124 | elsif remain.length > 2 && remain[0] == ?+
|
---|
125 | raise OpenSSL::X509::NameError,
|
---|
126 | "multi-valued RDN is not supported: #{dn}"
|
---|
127 | elsif remain.empty?
|
---|
128 | break
|
---|
129 | end
|
---|
130 | end
|
---|
131 | end
|
---|
132 | msg_dn = dn[0, dn.length - str.length] + " =>" + str
|
---|
133 | raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}"
|
---|
134 | end
|
---|
135 | return ary
|
---|
136 | end
|
---|
137 | end
|
---|
138 |
|
---|
139 | class <<self
|
---|
140 | def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE)
|
---|
141 | ary = OpenSSL::X509::Name::RFC2253DN.scan(str)
|
---|
142 | self.new(ary, template)
|
---|
143 | end
|
---|
144 |
|
---|
145 | def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE)
|
---|
146 | ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) }
|
---|
147 | self.new(ary, template)
|
---|
148 | end
|
---|
149 |
|
---|
150 | alias parse parse_openssl
|
---|
151 | end
|
---|
152 | end
|
---|
153 | end
|
---|
154 | end
|
---|