summaryrefslogtreecommitdiff
path: root/vendor/acme-client/lib/acme/client/crypto.rb
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/acme-client/lib/acme/client/crypto.rb')
-rw-r--r--vendor/acme-client/lib/acme/client/crypto.rb98
1 files changed, 98 insertions, 0 deletions
diff --git a/vendor/acme-client/lib/acme/client/crypto.rb b/vendor/acme-client/lib/acme/client/crypto.rb
new file mode 100644
index 0000000..dfa5cdc
--- /dev/null
+++ b/vendor/acme-client/lib/acme/client/crypto.rb
@@ -0,0 +1,98 @@
+class Acme::Client::Crypto
+ attr_reader :private_key
+
+ def initialize(private_key)
+ @private_key = private_key
+ end
+
+ def generate_signed_jws(header:, payload:)
+ header = { typ: 'JWT', alg: jws_alg, jwk: jwk }.merge(header)
+
+ encoded_header = urlsafe_base64(header.to_json)
+ encoded_payload = urlsafe_base64(payload.to_json)
+ signature_data = "#{encoded_header}.#{encoded_payload}"
+
+ signature = private_key.sign digest, signature_data
+ encoded_signature = urlsafe_base64(signature)
+
+ {
+ protected: encoded_header,
+ payload: encoded_payload,
+ signature: encoded_signature
+ }.to_json
+ end
+
+ def thumbprint
+ urlsafe_base64 digest.digest(jwk.to_json)
+ end
+
+ def digest
+ OpenSSL::Digest::SHA256.new
+ end
+
+ def urlsafe_base64(data)
+ Base64.urlsafe_encode64(data).sub(/[\s=]*\z/, '')
+ end
+
+ private
+
+ def jws_alg
+ { 'RSA' => 'RS256', 'EC' => 'ES256' }.fetch(jwk[:kty])
+ end
+
+ def jwk
+ @jwk ||= case private_key
+ when OpenSSL::PKey::RSA
+ rsa_jwk
+ when OpenSSL::PKey::EC
+ ec_jwk
+ else
+ raise ArgumentError, "Can't handle #{private_key} as private key, only OpenSSL::PKey::RSA and OpenSSL::PKey::EC"
+ end
+ end
+
+ def rsa_jwk
+ {
+ e: urlsafe_base64(public_key.e.to_s(2)),
+ kty: 'RSA',
+ n: urlsafe_base64(public_key.n.to_s(2))
+ }
+ end
+
+ def ec_jwk
+ {
+ crv: curve_name,
+ kty: 'EC',
+ x: urlsafe_base64(coordinates[:x].to_s(2)),
+ y: urlsafe_base64(coordinates[:y].to_s(2))
+ }
+ end
+
+ def curve_name
+ {
+ 'prime256v1' => 'P-256',
+ 'secp384r1' => 'P-384',
+ 'secp521r1' => 'P-521'
+ }.fetch(private_key.group.curve_name) { raise ArgumentError, 'Unknown EC curve' }
+ end
+
+ # rubocop:disable Metrics/AbcSize
+ def coordinates
+ @coordinates ||= begin
+ hex = public_key.to_bn.to_s(16)
+ data_len = hex.length - 2
+ hex_x = hex[2, data_len / 2]
+ hex_y = hex[2 + data_len / 2, data_len / 2]
+
+ {
+ x: OpenSSL::BN.new([hex_x].pack('H*'), 2),
+ y: OpenSSL::BN.new([hex_y].pack('H*'), 2)
+ }
+ end
+ end
+ # rubocop:enable Metrics/AbcSize
+
+ def public_key
+ @public_key ||= private_key.public_key
+ end
+end