Class: MobileId::Cert

Inherits:
Object
  • Object
show all
Defined in:
lib/mobile_id/cert.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base64_cert, live:) ⇒ Cert

Returns a new instance of Cert.



52
53
54
55
56
# File 'lib/mobile_id/cert.rb', line 52

def initialize(base64_cert, live:)
  self.cert = OpenSSL::X509::Certificate.new(Base64.decode64(base64_cert))
  verify!(cert, live: live)
  build_cert_subject
end

Instance Attribute Details

#certObject

Returns the value of attribute cert.



50
51
52
# File 'lib/mobile_id/cert.rb', line 50

def cert
  @cert
end

#subjectObject

Returns the value of attribute subject.



50
51
52
# File 'lib/mobile_id/cert.rb', line 50

def subject
  @subject
end

Class Method Details

.build_store(paths) ⇒ Object



40
41
42
43
44
45
46
47
# File 'lib/mobile_id/cert.rb', line 40

def build_store(paths)
  store = OpenSSL::X509::Store.new
  paths.each do |path|
    cert = OpenSSL::X509::Certificate.new(File.read(path))
    store.add_cert(cert)
  end
  store
end

.live_storeObject



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/mobile_id/cert.rb', line 10

def live_store
  @live_store ||=
    build_store(
      [
        File.join(root_path, 'EE_Certification_Centre_Root_CA.pem.crt'),
        File.join(root_path, 'EE-GovCA2018.pem.crt'),
        File.join(root_path, 'EID-SK_2011.pem.crt'),
        File.join(root_path, 'EID-SK_2016.pem.crt'),
        File.join(root_path, 'esteid2018.pem.crt'),
        File.join(root_path, 'ESTEID-SK_2011.pem.crt'),
        File.join(root_path, 'ESTEID-SK_2015.pem.crt'),
        File.join(root_path, 'KLASS3-SK_2010_EECCRCA.pem.crt'),
        File.join(root_path, 'KLASS3-SK_2010_EECCRCA_SHA384.pem.crt'),
        File.join(root_path, 'KLASS3-SK_2016_EECCRCA_SHA384.pem.crt'),
        File.join(root_path, 'KLASS3-SK.pem.crt'),
        File.join(root_path, 'NQ-SK_2016.pem.crt')
      ]
    )
end

.root_pathObject



6
7
8
# File 'lib/mobile_id/cert.rb', line 6

def root_path
  @root_path ||= File.expand_path('certs', __dir__)
end

.test_storeObject



30
31
32
33
34
35
36
37
38
# File 'lib/mobile_id/cert.rb', line 30

def test_store
  @test_store ||=
    build_store(
      [
        File.join(root_path, 'TEST_of_EE_Certification_Centre_Root_CA.pem.crt'),
        File.join(root_path, 'TEST_of_ESTEID-SK_2015.pem.crt')
      ]
    )
end

Instance Method Details

#common_nameObject



112
113
114
# File 'lib/mobile_id/cert.rb', line 112

def common_name
  subject['CN']
end

#countryObject



108
109
110
# File 'lib/mobile_id/cert.rb', line 108

def country
  subject['C'].tr(',', ' ')
end

#cvc_to_der(cvc) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/mobile_id/cert.rb', line 89

def cvc_to_der(cvc)
  sign_hex = cvc.unpack1('H*')
  half = sign_hex.size / 2
  i = [OpenSSL::ASN1::Integer.new(sign_hex[0...half].to_i(16)),
       OpenSSL::ASN1::Integer.new(sign_hex[half..sign_hex.size].to_i(16))]
  seq = OpenSSL::ASN1::Sequence.new(i)
  seq.to_der
end

#given_nameObject Also known as: first_name



98
99
100
# File 'lib/mobile_id/cert.rb', line 98

def given_name
  subject['GN'].tr(',', ' ')
end

#organizational_unitObject



116
117
118
# File 'lib/mobile_id/cert.rb', line 116

def organizational_unit
  subject['OU']
end

#serial_numberObject Also known as: personal_code



120
121
122
# File 'lib/mobile_id/cert.rb', line 120

def serial_number
  subject['serialNumber']
end

#surnameObject Also known as: last_name



103
104
105
# File 'lib/mobile_id/cert.rb', line 103

def surname
  subject['SN'].tr(',', ' ')
end

#verify!(cert, live:) ⇒ Object

Raises:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/mobile_id/cert.rb', line 58

def verify!(cert, live:)
  if live == true
    raise Error, 'User certificate is not valid' unless self.class.live_store.verify(cert)
  else
    unless self.class.test_store.verify(cert) || self.class.live_store.verify(cert)
      raise Error,
            'User certificate is not valid'
    end
  end

  raise Error, 'User certificate is not valid [check_key]' unless cert.public_key.check_key
  raise Error, 'User certificate is expired' unless (cert.not_before...cert.not_after).include?(Time.now)

  true
end

#verify_signature!(signature_base64, doc) ⇒ Object

Raises:



74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/mobile_id/cert.rb', line 74

def verify_signature!(signature_base64, doc)
  signature = Base64.decode64(signature_base64)
  digest = OpenSSL::Digest::SHA256.new(doc)

  valid =
    begin
      cert.public_key.verify(digest, signature, doc)
    rescue OpenSSL::PKey::PKeyError
      der_signature = cvc_to_der(signature) # Probably signature is CVC encoded
      cert.public_key.verify(digest, der_signature, doc)
    end

  raise Error, 'We could not verify user signature' unless valid
end