[18425] | 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
|
---|