Class: R509::CertificateAuthority::Signer

Inherits:
Object
  • Object
show all
Defined in:
lib/r509/certificateauthority.rb

Overview

Contains the certification authority signing operation methods

Instance Method Summary (collapse)

Constructor Details

- (Signer) initialize(config = nil)

A new instance of Signer

Parameters:



12
13
14
15
16
17
18
19
20
21
# File 'lib/r509/certificateauthority.rb', line 12

def initialize(config=nil)
  @config = config

  if not @config.nil? and not @config.kind_of?(R509::Config::CaConfig)
    raise R509::R509Error, "config must be a kind of R509::Config::CaConfig or nil (for self-sign only)"
  end
  if not @config.nil? and not @config.ca_cert.has_private_key?
    raise R509::R509Error, "You must have a private key associated with your CA certificate to issue"
  end
end

Instance Method Details

- (R509::Cert) selfsign(options)

Self-signs a CSR

Parameters:

  • options (Hash)

    a customizable set of options

Options Hash (options):

  • :csr (R509::Csr)
  • :message_digest (String)

    the message digest to use for this certificate (defaults to sha1)

  • :serial (String)

    the serial number you want to issue the certificate with (defaults to random)

  • :not_before (Time)

    the notBefore for the certificate (defaults to now)

  • :not_after (Time)

    the notAfter for the certificate (defaults to 1 year)

  • :san_names (Array)

    Optional array of subject alternative names

Returns:



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
# File 'lib/r509/certificateauthority.rb', line 124

def selfsign(options)
  if not options.kind_of?(Hash)
    raise ArgumentError, "You must pass a hash of options consisting of at minimum :csr"
  end
  csr = options[:csr]
  if csr.key.nil?
    raise ArgumentError, 'CSR must also have a private key to self sign'
  end
  cert = build_cert(
    :subject => csr.subject.name,
    :issuer => csr.subject.name,
    :not_before => options[:not_before],
    :not_after => options[:not_after],
    :public_key => csr.public_key,
    :serial => options[:serial]
  )

  if options.has_key?(:san_names)
    san_names = options[:san_names]
  else
    san_names = csr.san_names
  end

  build_extensions(
    :subject_certificate => cert,
    :issuer_certificate => cert,
    :basic_constraints => "CA:TRUE",
    :san_names => san_names
  )


  if options.has_key?(:message_digest)
    message_digest = R509::MessageDigest.new(options[:message_digest])
  else
    message_digest = R509::MessageDigest.new('sha1')
  end

  # Csr#key returns R509::PrivateKey and #key on that returns OpenSSL object we need
  cert.sign( csr.key.key, message_digest.digest )
  R509::Cert.new(:cert => cert)
end

- (R509::Cert) sign(options)

Signs a CSR

Parameters:

  • options (Hash)

    a customizable set of options

Options Hash (options):

  • :csr (R509::Csr)
  • :spki (R509::Spki)
  • :profile_name (String)

    The CA profile you want to use (eg "server in your config)

  • :data_hash (Hash)

    a hash containing the subject and SAN names you want encoded for this cert. Generate by calling Csr#to_hash or Spki#to_hash

  • :message_digest (String)

    the message digest to use for this certificate instead of the config's default

  • :serial (String)

    the serial number you want to issue the certificate with

  • :not_before (Time)

    the notBefore for the certificate

  • :not_after (Time)

    the notAfter for the certificate

Returns:



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
# File 'lib/r509/certificateauthority.rb', line 33

def sign(options)
  if @config.nil?
    raise R509::R509Error, "When instantiating the signer without a config you can only call #selfsign"
  elsif @config.num_profiles == 0
    raise R509::R509Error, "You must have at least one CaProfile on your CaConfig to issue"
  end

  if options.has_key?(:csr) and options.has_key?(:spki)
    raise ArgumentError, "You can't pass both :csr and :spki"
  elsif not options.has_key?(:csr) and not options.has_key?(:spki)
    raise ArgumentError, "You must supply either :csr or :spki"
  elsif options.has_key?(:csr)
    if not options[:csr].kind_of?(R509::Csr)
      raise ArgumentError, "You must pass an R509::Csr object for :csr"
    else
      signable_object = options[:csr]
    end
  elsif not options.has_key?(:csr) and options.has_key?(:spki)
    if not options[:spki].kind_of?(R509::Spki)
      raise ArgumentError, "You must pass an R509::Spki object for :spki"
    else
      signable_object = options[:spki]
    end
  end

  if options.has_key?(:data_hash)
    san_names = options[:data_hash][:san_names]
    subject = options[:data_hash][:subject]
  else
    san_names = signable_object.to_hash[:san_names]
    subject = signable_object.to_hash[:subject]
  end



  if options.has_key?(:csr) and not options[:csr].verify_signature
    raise R509::R509Error, "Certificate request signature is invalid."
  end

  # prior to OpenSSL 1.0 DSA could only use DSS1 (aka SHA1) signatures. post-1.0 anything
  # goes but at the moment we don't enforce this restriction so an OpenSSL error could
  # bubble up if they do it wrong.
  if options.has_key?(:message_digest)
    message_digest = R509::MessageDigest.new(options[:message_digest])
  else
    message_digest = R509::MessageDigest.new(@config.message_digest)
  end

  profile = @config.profile(options[:profile_name])

  validated_subject = validate_subject(subject,profile)

  cert = build_cert(
    :subject => validated_subject.name,
    :issuer => @config.ca_cert.subject,
    :not_before => options[:not_before],
    :not_after => options[:not_after],
    :public_key => signable_object.public_key,
    :serial => options[:serial]
  )

  basic_constraints = profile.basic_constraints
  key_usage = profile.key_usage
  extended_key_usage = profile.extended_key_usage
  certificate_policies = profile.certificate_policies

  build_extensions(
    :subject_certificate => cert,
    :issuer_certificate => @config.ca_cert.cert,
    :basic_constraints => basic_constraints,
    :key_usage => key_usage,
    :extended_key_usage => extended_key_usage,
    :certificate_policies => certificate_policies,
    :san_names => san_names
  )


  #@config.ca_cert.key.key ... ugly. ca_cert returns R509::Cert
  # #key returns R509::PrivateKey and #key on that returns OpenSSL object we need
  cert.sign( @config.ca_cert.key.key, message_digest.digest )
  R509::Cert.new(:cert => cert)
end