require "openssl/lib_crypto" # :nodoc: module OpenSSL::X509 # :nodoc: class Name # Parses entries in string and initializes a Name object. # # Example: # ``` # require "openssl" # # OpenSSL::X509::Name.parse("CN=nobody/DC=example") # ``` def self.parse(string : String) : Name new.tap do |name| string.split('/') do |entry| oid, _, value = entry.partition('=') name.add_entry(oid, value) end end end def initialize @name = LibCrypto.x509_name_new raise Error.new("X509_NAME_new") if @name.null? end def initialize(name : LibCrypto::X509_NAME) @name = LibCrypto.x509_name_dup(name) raise Error.new("X509_NAME_dup") if @name.null? end def finalize LibCrypto.x509_name_free(@name) end def dup self.class.new(@name) end def to_unsafe @name end # Adds a new entry. # # Example: # ``` # name = OpenSSL::X509::Name.new # name.add_entry "CN", "Nobody" # name.add_entry "DC", "example" # ``` def add_entry(oid : String, value : String) : Nil type = LibCrypto::MBSTRING_UTF8 ret = LibCrypto.x509_name_add_entry_by_txt(@name, oid, type, value, value.bytesize, -1, 0) raise Error.new("X509_NAME_add_entry_by_txt") if ret.null? end # Returns entries as an Array of oid, value pairs. # # Example: # ``` # name = OpenSSL::X509::Name.parse("CN=Nobody/DC=example") # name.to_a # => [{"CN", "Nobody"}, {"DC", "example"}] # ``` def to_a : Array({String, String}) count = LibCrypto.x509_name_entry_count(@name) raise Error.new("X509_NAME_entry_count") if count < 0 long_name = Bytes.new(512) Array(Tuple(String, String)).new(count) do |i| entry = LibCrypto.x509_name_get_entry(@name, i) raise Error.new("X509_NAME_get_entry") if entry.null? obj = LibCrypto.x509_name_entry_get_object(entry) LibCrypto.i2t_asn1_object(long_name, long_name.size, obj) nid = LibCrypto.obj_ln2nid(long_name) if nid == LibCrypto::NID_undef oid = String.new(long_name) else short_name = LibCrypto.obj_nid2sn(nid) oid = String.new(short_name) end asn1 = LibCrypto.x509_name_entry_get_data(entry) str = LibCrypto.asn1_string_data(asn1) str_len = LibCrypto.asn1_string_length(asn1) {oid, String.new(str, str_len)} end end end end