Class: SCEP::PKIOperation::Base

Inherits:
Object
  • Object
show all
Includes:
Loggable
Defined in:
lib/scep/pki_operation/base.rb

Overview

Base class that contains commonalities between both requests and repsonses:

  • RA Certificate
  • RA Private Key

Direct Known Subclasses

Request, Response

Constant Summary collapse

DEFAULT_CIPHER_ALGORITHM =
'aes-256-cbc'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Loggable

#logger

Constructor Details

#initialize(ra_keypair) ⇒ Base

Creates a new payload

Parameters:



32
33
34
# File 'lib/scep/pki_operation/base.rb', line 32

def initialize(ra_keypair)
  @ra_keypair = ra_keypair
end

Instance Attribute Details

#p7encOpenSSL::PKCS7 (readonly)

The last encrypted payload

Returns:

  • (OpenSSL::PKCS7)


24
25
26
# File 'lib/scep/pki_operation/base.rb', line 24

def p7enc
  @p7enc
end

#p7signOpenSSL::PKCS7 (readonly)

The last signed payload

Returns:

  • (OpenSSL::PKCS7)


20
21
22
# File 'lib/scep/pki_operation/base.rb', line 20

def p7sign
  @p7sign
end

#ra_keypairKeypair

Our keypair

Returns:



16
17
18
# File 'lib/scep/pki_operation/base.rb', line 16

def ra_keypair
  @ra_keypair
end

#x509_storeOpenSSL::X509::Store

Gets an x509 store. Defaults to a store with system default paths. Used for decryption.

Returns:

  • (OpenSSL::X509::Store)


39
40
41
# File 'lib/scep/pki_operation/base.rb', line 39

def x509_store
  @x509_store ||= OpenSSL::X509::Store.new
end

Class Method Details

.create_default_cipherOpenSSL::Cipher (protected)

Creates an OpenSSL::Cipher using the DEFAULT_CIPHER_ALGORITHM. It's best to create a new Cipher object for every new encryption call so that we don't re-use sensitive data (IV's) [citation needed].

Returns:

  • (OpenSSL::Cipher)


105
106
107
# File 'lib/scep/pki_operation/base.rb', line 105

def self.create_default_cipher
  OpenSSL::Cipher.new(DEFAULT_CIPHER_ALGORITHM)
end

Instance Method Details

#add_verification_certificate(cert) ⇒ Object Also known as: verify_against

Adds a certificate to verify against

Parameters:

  • cert (OpenSSL::X509::Certificate)


45
46
47
# File 'lib/scep/pki_operation/base.rb', line 45

def add_verification_certificate(cert)
  x509_store.add_cert(cert)
end

#check_if_recipient_matches_ra_certificate_name(p7enc) ⇒ Object (protected)



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/scep/pki_operation/base.rb', line 111

def check_if_recipient_matches_ra_certificate_name(p7enc)
  if p7enc.recipients.nil? || p7enc.recipients.empty?
    logger.warn 'SCEP request does not have any recipient info - ' \
      'cannot determine if SCEP request is intended for us'
    return false
  end

  matched = false
  names = p7enc.recipients.map(&:issuer).each do |name|
    if name.cmp(ra_keypair.certificate.subject) == 0
      matched = true
      break
    end
  end

  unless matched
    logger.warn 'SCEP request does not appear to be addressed to us! ' \
      "RA Cert: #{ra_keypair.certificate.subject.to_s}, Recipients: [#{names.map(&:to_s).join(', ')}]"
  end
  matched
end

#sign_and_encrypt_raw(raw_data, target_encryption_certs, cipher = nil) ⇒ OpenSSL::PKCS7 (protected)

Signs and encrypts the given raw data

Parameters:

  • raw_data (String)

    the raw data to sign and encrypt

  • target_encryption_certs (OpenSSL::X509::Certificate)

    the cert(s) to encrypt for

  • cipher (OpenSSL::Cipher::Cipher) (defaults to: nil)

    the cipher to use. Defaults to create_default_cipher

Returns:

  • (OpenSSL::PKCS7)

    the signed and encrypted payload



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/scep/pki_operation/base.rb', line 85

def sign_and_encrypt_raw(raw_data, target_encryption_certs, cipher = nil)
  cipher ||= self.class.create_default_cipher

  encrypted = OpenSSL::PKCS7.encrypt(
    wrap_array(target_encryption_certs),
    raw_data,
    cipher,
    OpenSSL::PKCS7::BINARY)

  OpenSSL::PKCS7.sign(
    ra_keypair.certificate,
    ra_keypair.private_key,
    encrypted.to_der,
    [ra_keypair.certificate],
    OpenSSL::PKCS7::BINARY)
end

#unsign_and_unencrypt_raw(signed_and_encrypted_csr, verify = true) ⇒ String (protected)

Takes a raw binary string and returns the raw, unencrypted data

Parameters:

  • signed_and_encrypted_csr (String)

    the signed and encrypted data

  • verify (Boolean) (defaults to: true)

    if TRUE, verifies the signed PKCS7 payload against the #x509_store

Returns:

  • (String)

    the decrypted and unsigned data (original format)

Raises:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/scep/pki_operation/base.rb', line 58

def unsign_and_unencrypt_raw(signed_and_encrypted_csr, verify = true)
  # Remove signature
  @p7sign = OpenSSL::PKCS7.new(signed_and_encrypted_csr)

  flags = OpenSSL::PKCS7::BINARY
  flags |= OpenSSL::PKCS7::NOVERIFY unless verify

  # See http://openssl.6102.n7.nabble.com/pkcs7-verification-with-ruby-td28455.html
  verified = @p7sign.verify([], x509_store, nil, flags)

  if !verified
    raise SCEP::PKIOperation::VerificationFailed,
      'Unable to verify signature against certificate store - did you add the correct certificates?'
  end


  # Decrypt
  @p7enc   = OpenSSL::PKCS7.new(@p7sign.data)
  check_if_recipient_matches_ra_certificate_name(@p7enc)
  @p7enc.decrypt(ra_keypair.private_key, ra_keypair.certificate, OpenSSL::PKCS7::BINARY)
end

#wrap_array(object) ⇒ Object (protected)

Same as Array.wrap



135
136
137
138
139
140
141
142
143
# File 'lib/scep/pki_operation/base.rb', line 135

def wrap_array(object)
  if object.nil?
    []
  elsif object.respond_to?(:to_ary)
    object.to_ary || [object]
  else
    [object]
  end
end