Class: MiniCa::Certificate

Inherits:
Object
  • Object
show all
Defined in:
lib/mini_ca/certificate.rb

Constant Summary collapse

DIGEST =
OpenSSL::Digest::SHA256

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cn, sans: nil, issuer: nil, ca: false, serial: nil, not_before: nil, not_after: nil, country: nil, state: nil, location: nil, organization: nil) ⇒ Certificate

rubocop:disable ParameterLists



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/mini_ca/certificate.rb', line 8

def initialize(
  cn,
  sans: nil,
  issuer: nil,
  ca: false,
  serial: nil,
  not_before: nil,
  not_after: nil,
  country: nil,
  state: nil,
  location: nil,
  organization: nil
)
  @key = OpenSSL::PKey::RSA.new(2048)
  @x509 = OpenSSL::X509::Certificate.new
  @issuer = issuer
  @ca = ca
  @counter = 0

  x509.version = 0x2
  x509.serial = serial || 0

  x509.public_key = key.public_key

  x509.subject = OpenSSL::X509::Name.new

  [
    ['CN', cn],
    ['C', country],
    ['ST', state],
    ['L', location],
    ['O', organization]
  ].each do |prop, value|
    next if value.nil?
    x509.subject = x509.subject.add_entry(prop, value)
  end

  x509.issuer = issuer ? issuer.x509.subject : x509.subject

  if issuer
    not_before ||= issuer.x509.not_before
    not_after ||= issuer.x509.not_after

    if issuer.x509.not_before > not_before
      raise Error, 'Certificate cannot become valid before issuer'
    end

    if issuer.x509.not_after < not_after
      raise Error, 'Certificate cannot expire after issuer'
    end
  else
    not_before ||= Time.now - 3600 * 24
    not_after ||= Time.now + 3600 + 24
  end

  x509.not_before = not_before
  x509.not_after = not_after

  ef = OpenSSL::X509::ExtensionFactory.new
  ef.subject_certificate = x509

  sans = (sans || []) + ["DNS:#{cn}"]

  exts = if ca
           [
             ef.create_extension('basicConstraints', 'CA:TRUE', true)
           ]
         else
           [
             ef.create_extension('basicConstraints', 'CA:FALSE', true),
             ef.create_extension('subjectAltName', sans.join(','), false)
           ]
         end

  exts.each { |e| x509.add_extension(e) }

  signing_key = issuer ? issuer.key : key
  x509.sign signing_key, DIGEST.new
end

Instance Attribute Details

#caObject (readonly)

Returns the value of attribute ca.



5
6
7
# File 'lib/mini_ca/certificate.rb', line 5

def ca
  @ca
end

#issuerObject (readonly)

Returns the value of attribute issuer.



5
6
7
# File 'lib/mini_ca/certificate.rb', line 5

def issuer
  @issuer
end

#keyObject (readonly)

Returns the value of attribute key.



5
6
7
# File 'lib/mini_ca/certificate.rb', line 5

def key
  @key
end

#x509Object (readonly)

Returns the value of attribute x509.



5
6
7
# File 'lib/mini_ca/certificate.rb', line 5

def x509
  @x509
end

Instance Method Details

#bundleObject



109
110
111
# File 'lib/mini_ca/certificate.rb', line 109

def bundle
  [self] + chain
end

#bundle_pemObject



121
122
123
# File 'lib/mini_ca/certificate.rb', line 121

def bundle_pem
  bundle.map(&:x509).map(&:to_s).join('')
end

#chainObject



100
101
102
103
104
105
106
107
# File 'lib/mini_ca/certificate.rb', line 100

def chain
  bits = []
  this_cert = self
  until (this_cert = this_cert.issuer).nil?
    bits << this_cert
  end
  bits[0...-1]
end

#chain_pemObject



117
118
119
# File 'lib/mini_ca/certificate.rb', line 117

def chain_pem
  chain.map(&:x509).map(&:to_s).join('')
end

#issue(cn, **opts) ⇒ Object

rubocop:enable ParameterLists



89
90
91
92
93
# File 'lib/mini_ca/certificate.rb', line 89

def issue(cn, **opts)
  raise 'CA must be set to use #issue' unless ca
  @counter += 1
  Certificate.new(cn, issuer: self, serial: @counter, **opts)
end

#key_pemObject



125
126
127
# File 'lib/mini_ca/certificate.rb', line 125

def key_pem
  key.to_s
end

#storeObject



95
96
97
98
# File 'lib/mini_ca/certificate.rb', line 95

def store
  raise 'CA must be set to use #store' unless ca
  OpenSSL::X509::Store.new.tap { |store| store.add_cert(x509) }
end

#x509_pemObject



113
114
115
# File 'lib/mini_ca/certificate.rb', line 113

def x509_pem
  x509.to_s
end