File: create_certs.rb

package info (click to toggle)
rubygems 3.6.7-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 37,448 kB
  • sloc: ruby: 141,650; sh: 94; makefile: 28
file content (173 lines) | stat: -rw-r--r-- 4,841 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# frozen_string_literal: true

require "openssl"

class CertificateBuilder
  attr_reader :start

  def initialize(key_size = 2048)
    @start          = Time.utc 2012, 1, 1, 0, 0, 0
    @end_of_time    = Time.utc 9999, 12, 31, 23, 59, 59
    @end_of_time_32 = Time.utc 2038, 1, 19, 3, 14, 7

    @key_size = key_size
    @serial = 0
  end

  def create_certificates(key, subject, issuer_key = key, issuer_cert = nil,
    not_before: @start, not_after: :end_of_time, is_ca: false)
    certificates = []

    not_before, not_before_32 = validity_for not_before
    not_after,  not_after_32  = validity_for not_after
    issuer_cert, issuer_cert_32 = issuer_cert

    certificates <<
      create_certificate(key, subject, issuer_key, issuer_cert,
                         not_before, not_after, is_ca)
    certificates <<
      create_certificate(key, subject, issuer_key, issuer_cert_32,
                         not_before_32, not_after_32, is_ca)

    certificates
  end

  def create_certificate(key, subject, issuer_key, issuer_cert,
    not_before, not_after, is_ca)
    cert = OpenSSL::X509::Certificate.new
    issuer_cert ||= cert # if not specified, create self signing cert

    cert.version    = 2
    cert.serial     = 0

    cert.not_before = not_before
    cert.not_after  = not_after

    cert.serial = next_serial

    cert.public_key = key.public_key

    cert.subject = OpenSSL::X509::Name.new [%W[CN #{subject}], %w[DC example]]
    cert.issuer  = issuer_cert.subject

    ef = OpenSSL::X509::ExtensionFactory.new issuer_cert, cert

    cert.extensions = [
      ef.create_extension("subjectAltName", "email:#{subject}@example"),
      ef.create_extension("subjectKeyIdentifier", "hash"),
    ]

    if cert != issuer_cert # not self-signed cert
      cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always")
    end

    if is_ca
      cert.add_extension ef.create_extension("basicConstraints", "CA:TRUE", true)
      cert.add_extension ef.create_extension("keyUsage", "keyCertSign", true)
    end

    cert.sign issuer_key, "SHA256"

    puts "created cert - subject: #{cert.subject}, issuer: #{cert.issuer}"
    cert
  end

  def create_key
    puts "creating key"
    OpenSSL::PKey::RSA.new @key_size
  end

  def create_keys(names)
    keys = {}

    names.each do |name|
      keys[name] = create_key
    end

    keys
  end

  def next_serial
    serial = @serial
    @serial += 1
    serial
  end

  def validity_for(time)
    if time == :end_of_time
      validity    = @end_of_time
      validity_32 = @end_of_time_32
    else
      validity = validity_32 = time
    end

    [validity, validity_32]
  end
end

cb = CertificateBuilder.new

keys = cb.create_keys [
  :alternate,
  :child,
  :grandchild,
  :invalid,
  :invalidchild,
  :private,
]

keys[:public] = keys[:private].public_key

certs = {}
certs[:public] =
  cb.create_certificates(keys[:private], "nobody",
                         is_ca: true)
certs[:child] =
  cb.create_certificates(keys[:child], "child",
                         keys[:private], certs[:public],
                         is_ca: true)
certs[:alternate] =
  cb.create_certificates(keys[:alternate], "alternate")
certs[:expired] =
  cb.create_certificates(keys[:private], "nobody",
                         not_before: Time.at(0),
                         not_after: Time.at(0))
certs[:future] =
  cb.create_certificates(keys[:private], "nobody",
                         not_before: :end_of_time,
                         not_after: :end_of_time)
certs[:invalid_issuer] =
  cb.create_certificates(keys[:invalid], "invalid",
                         keys[:invalid], certs[:public],
                         is_ca: true)
certs[:grandchild] =
  cb.create_certificates(keys[:grandchild], "grandchild",
                         keys[:child], certs[:child])
certs[:invalid_signer] =
  cb.create_certificates(keys[:invalid], "invalid",
                         keys[:private], certs[:invalid])
certs[:invalidchild] =
  cb.create_certificates(keys[:invalidchild], "invalidchild",
                         keys[:invalid], certs[:child])
certs[:wrong_key] =
  cb.create_certificates(keys[:alternate], "nobody")

base_dir = "test/rubygems"

keys.each do |name, key|
  dest = File.join base_dir, "#{name}_key.pem"
  File.write dest, key.to_pem
end

# Create an encrypted private key protected by a passphrase from the new keys[:private]
# it has to be the same as is in # test/rubygems/helper.rb in PRIVATE_KEY_PASSPHRASE
dest = File.join base_dir, "encrypted_private_key.pem"
File.write dest, keys[:private].to_pem(OpenSSL::Cipher.new("aes-256-cbc"), "Foo bar")

certs.each do |name, (cert, cert_32)|
  dest = File.join base_dir, "#{name}_cert.pem"
  File.write dest, cert.to_pem

  dest = File.join base_dir, "#{name}_cert_32.pem"
  File.write dest, cert_32.to_pem
end