Module: GlobiGuard::Entitlements

Defined in:
lib/globiguard.rb

Class Method Summary collapse

Class Method Details

.base64url_decode(value) ⇒ Object



240
241
242
# File 'lib/globiguard.rb', line 240

def base64url_decode(value)
  Base64.urlsafe_decode64(value + ("=" * ((4 - value.length % 4) % 4)))
end

.verify_ed25519!(raw_public_key, signing_input, signature) ⇒ Object



231
232
233
234
235
236
237
238
# File 'lib/globiguard.rb', line 231

def verify_ed25519!(raw_public_key, signing_input, signature)
  prefix = [48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0].pack("C*")
  key = OpenSSL::PKey.read(prefix + raw_public_key)
  verified = key.verify(nil, signature, signing_input)
  raise OpenSSL::PKey::PKeyError, "Invalid entitlement manifest signature." unless verified
rescue NoMethodError, OpenSSL::PKey::PKeyError => e
  raise OpenSSL::PKey::PKeyError, "Ruby/OpenSSL Ed25519 verification is unavailable or failed: #{e.message}"
end

.verify_signed_manifest(compact_jws, public_keys_by_id:) ⇒ Object

Raises:

  • (ArgumentError)


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/globiguard.rb', line 214

def verify_signed_manifest(compact_jws, public_keys_by_id:)
  parts = compact_jws.split(".")
  raise ArgumentError, "Entitlement manifest must be compact JWS." unless parts.length == 3
  header = JSON.parse(base64url_decode(parts[0]))
  raise ArgumentError, "Entitlement manifest must use EdDSA." unless header["alg"] == "EdDSA"
  public_key = public_keys_by_id.fetch(header.fetch("kid"))
  signing_input = "#{parts[0]}.#{parts[1]}"
  signature = base64url_decode(parts[2])
  verify_ed25519!(base64url_decode(public_key), signing_input, signature)
  payload = JSON.parse(base64url_decode(parts[1]))
  raise ArgumentError, "Unsupported entitlement manifest schema." unless payload["schema"] == "globiguard.entitlement_manifest.v1"
  now = Time.now.to_i
  raise ArgumentError, "Entitlement manifest is not active yet." if payload["nbf"] && payload["nbf"].to_i > now
  raise ArgumentError, "Entitlement manifest is expired." if payload["exp"] && payload["exp"].to_i <= now
  payload
end