Module: Acme::Client::Util

Extended by:
Util
Included in:
Util
Defined in:
lib/acme/client/util.rb

Constant Summary collapse

/<(.*?)>\s?;\s?rel="([\w-]+)"/

Instance Method Summary collapse

Instance Method Details

#ari_certificate_identifier(certificate) ⇒ Object

Generates a certificate identifier for ACME Renewal Information (ARI) as per RFC 9773. The identifier is constructed by extracting the Authority Key Identifier (AKI) from the certificate extension, and the DER-encoded serial number (without tag and length bytes). Both values are base64url-encoded and concatenated with a period separator.

certificate - An OpenSSL::X509::Certificate instance or PEM string.

Returns a string in the format: base64url(AKI).base64url(serial)

Raises:

  • (ArgumentError)


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
# File 'lib/acme/client/util.rb', line 44

def ari_certificate_identifier(certificate)
  cert = if certificate.is_a?(OpenSSL::X509::Certificate)
    certificate
  else
    OpenSSL::X509::Certificate.new(certificate)
  end

  aki_ext = cert.extensions.find { |ext| ext.oid == 'authorityKeyIdentifier' }
  raise ArgumentError, 'Certificate does not have an Authority Key Identifier extension' unless aki_ext

  aki_value = aki_ext.value
  hex_string = if aki_value =~ /keyid:([0-9A-Fa-f:]+)/
    $1
  elsif aki_value =~ /^[0-9A-Fa-f:]+$/
    aki_value
  else
    raise ArgumentError, 'Could not parse Authority Key Identifier'
  end

  key_identifier = hex_string.split(':').map { |hex| hex.to_i(16).chr }.join
  serial_der = OpenSSL::ASN1::Integer.new(cert.serial).to_der
  serial_value = OpenSSL::ASN1.decode(serial_der).value.to_s(2)

  aki_b64 = urlsafe_base64(key_identifier)
  serial_b64 = urlsafe_base64(serial_value)

  "#{aki_b64}.#{serial_b64}"
end


11
12
13
14
15
16
17
# File 'lib/acme/client/util.rb', line 11

def decode_link_headers(link_header)
  link_header.split(',').each_with_object({}) { |entry, hash|
    _, link, name = *entry.match(LINK_MATCH)
    hash[name] ||= []
    hash[name].push(link)
  }
end

#set_public_key(obj, priv) ⇒ Object

Sets public key on CSR or cert.

obj - An OpenSSL::X509::Certificate or OpenSSL::X509::Request instance. priv - An OpenSSL::PKey::EC or OpenSSL::PKey::RSA instance.

Returns nothing.



25
26
27
28
29
30
31
32
33
34
# File 'lib/acme/client/util.rb', line 25

def set_public_key(obj, priv)
  case priv
  when OpenSSL::PKey::EC
    obj.public_key = priv
  when OpenSSL::PKey::RSA
    obj.public_key = priv.public_key
  else
    raise ArgumentError, 'priv must be EC or RSA'
  end
end

#urlsafe_base64(data) ⇒ Object



4
5
6
# File 'lib/acme/client/util.rb', line 4

def urlsafe_base64(data)
  Base64.urlsafe_encode64(data).sub(/[\s=]*\z/, '')
end