class Acme::Client::JWK::ECDSA
def coordinates
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
def initialize(private_key)
private_key - A OpenSSL::PKey::EC instance.
Instantiate a new ECDSA JWK.
def initialize(private_key) unless private_key.is_a?(OpenSSL::PKey::EC) raise ArgumentError, 'private_key must be a OpenSSL::PKey::EC' end unless @curve_params = KNOWN_CURVES[private_key.group.curve_name] raise ArgumentError, 'Unknown EC curve' end @private_key = private_key end
def jwa_alg
The name of the algorithm as needed for the `alg` member of a JWS object.
def jwa_alg @curve_params[:jwa_alg] end
def public_key
def public_key @private_key.public_key end
def sign(message)
message - A String message to sign.
Sign a message with the private key.
def sign(message) # DER encoded ASN.1 signature der = @private_key.sign(@curve_params[:digest].new, message) # ASN.1 SEQUENCE seq = OpenSSL::ASN1.decode(der) # ASN.1 INTs ints = seq.value # BigNumbers bns = ints.map(&:value) byte_size = (@private_key.group.degree + 7) / 8 # Binary R/S values r, s = bns.map { |bn| bn.to_s(2).rjust(byte_size, "\x00") } # JWS wants raw R/S concatenated. [r, s].join end
def to_h
Get this JWK as a Hash for JSON serialization.
def to_h { crv: @curve_params[:jwa_crv], kty: 'EC', x: Acme::Client::Util.urlsafe_base64(coordinates[:x].to_s(2)), y: Acme::Client::Util.urlsafe_base64(coordinates[:y].to_s(2)) } end