Module: PQCrypto::SPKI

Defined in:
lib/pq_crypto/spki.rb

Constant Summary collapse

PEM_LABEL =
"PUBLIC KEY"
PEM_BEGIN =
"-----BEGIN #{PEM_LABEL}-----"
PEM_END =
"-----END #{PEM_LABEL}-----"

Class Method Summary collapse

Class Method Details

.decode_der(der) ⇒ Object

Raises:



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
# File 'lib/pq_crypto/spki.rb', line 39

def decode_der(der)
  input = String(der).b
  outer = decode_asn1(input)
  raise SerializationError, "SPKI DER contains trailing data" unless outer.to_der.b == input
  raise SerializationError, "SPKI must be an ASN.1 SEQUENCE" unless outer.is_a?(OpenSSL::ASN1::Sequence)
  raise SerializationError, "SPKI SEQUENCE must contain exactly 2 elements" unless outer.value.size == 2

  algorithm_identifier, subject_public_key = outer.value
  algorithm = decode_algorithm_identifier(algorithm_identifier)
  entry = AlgorithmRegistry.fetch(algorithm)
  validate_public_key_algorithm!(algorithm, entry)

  unless subject_public_key.is_a?(OpenSSL::ASN1::BitString)
    raise SerializationError, "SPKI subjectPublicKey must be a BIT STRING"
  end
  unless subject_public_key.unused_bits.zero?
    raise SerializationError, "SPKI subjectPublicKey must have zero unused bits"
  end

  bytes = String(subject_public_key.value).b
  expected = entry.fetch(:public_key_bytes)
  unless bytes.bytesize == expected
    raise SerializationError,
          "Invalid #{algorithm.inspect} SPKI public key length: expected #{expected}, got #{bytes.bytesize}"
  end

  [algorithm, bytes]
end

.decode_pem(pem) ⇒ Object



68
69
70
71
# File 'lib/pq_crypto/spki.rb', line 68

def decode_pem(pem)
  der = der_from_pem(pem)
  decode_der(der)
end

.encode_der(algorithm_symbol, public_key_bytes) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/pq_crypto/spki.rb', line 12

def encode_der(algorithm_symbol, public_key_bytes)
  entry = AlgorithmRegistry.fetch(algorithm_symbol)
  validate_public_key_algorithm!(algorithm_symbol, entry)

  bytes = String(public_key_bytes).b
  expected = entry.fetch(:public_key_bytes)
  unless bytes.bytesize == expected
    raise SerializationError,
          "Invalid #{algorithm_symbol.inspect} public key length: expected #{expected}, got #{bytes.bytesize}"
  end

  OpenSSL::ASN1::Sequence.new([
    OpenSSL::ASN1::Sequence.new([
      OpenSSL::ASN1::ObjectId.new(AlgorithmRegistry.standard_oid(algorithm_symbol)),
    ]),
    OpenSSL::ASN1::BitString.new(bytes),
  ]).to_der.b
rescue OpenSSL::ASN1::ASN1Error => e
  raise SerializationError, e.message
end

.encode_pem(algorithm_symbol, public_key_bytes) ⇒ Object



33
34
35
36
37
# File 'lib/pq_crypto/spki.rb', line 33

def encode_pem(algorithm_symbol, public_key_bytes)
  der = encode_der(algorithm_symbol, public_key_bytes)
  body = encode_base64(der).scan(/.{1,64}/).join("\n")
  "#{PEM_BEGIN}\n#{body}\n#{PEM_END}\n"
end