Raised by Encoding
and String
methods when the string being transcoded contains a byte invalid for the either the source or target encoding.
Raised by transcoding methods when a named encoding does not correspond with a known converter.
OpenSSL::OCSP
implements Online Certificate Status Protocol requests and responses.
Creating and sending an OCSP
request requires a subject certificate that contains an OCSP
URL in an authorityInfoAccess extension and the issuer certificate for the subject certificate. First, load the issuer and subject certificates:
subject = OpenSSL::X509::Certificate.new subject_pem issuer = OpenSSL::X509::Certificate.new issuer_pem
To create the request we need to create a certificate ID for the subject certificate so the CA knows which certificate we are asking about:
digest = OpenSSL::Digest.new('SHA1') certificate_id = OpenSSL::OCSP::CertificateId.new subject, issuer, digest
Then create a request and add the certificate ID to it:
request = OpenSSL::OCSP::Request.new request.add_certid certificate_id
Adding a nonce to the request protects against replay attacks but not all CA process the nonce.
request.add_nonce
To submit the request to the CA for verification we need to extract the OCSP
URI
from the subject certificate:
ocsp_uris = subject.ocsp_uris require 'uri' ocsp_uri = URI ocsp_uris[0]
To submit the request we’ll POST the request to the OCSP
URI
(per RFC 2560). Note that we only handle HTTP requests and don’t handle any redirects in this example, so this is insufficient for serious use.
require 'net/http' http_response = Net::HTTP.start ocsp_uri.hostname, ocsp_uri.port do |http| http.post ocsp_uri.path, request.to_der, 'content-type' => 'application/ocsp-request' end response = OpenSSL::OCSP::Response.new http_response.body response_basic = response.basic
First we check if the response has a valid signature. Without a valid signature we cannot trust it. If you get a failure here you may be missing a system certificate store or may be missing the intermediate certificates.
store = OpenSSL::X509::Store.new store.set_default_paths unless response_basic.verify [], store then raise 'response is not signed by a trusted certificate' end
The response contains the status information (success/fail). We can display the status as a string:
puts response.status_string #=> successful
Next we need to know the response details to determine if the response matches our request. First we check the nonce. Again, not all CAs support a nonce. See Request#check_nonce
for the meanings of the return values.
p request.check_nonce basic_response #=> value from -1 to 3
Then extract the status information for the certificate from the basic response.
single_response = basic_response.find_response(certificate_id) unless single_response raise 'basic_response does not have the status for the certificate' end
Then check the validity. A status issued in the future must be rejected.
unless single_response.check_validity raise 'this_update is in the future or next_update time has passed' end case single_response.cert_status when OpenSSL::OCSP::V_CERTSTATUS_GOOD puts 'certificate is still valid' when OpenSSL::OCSP::V_CERTSTATUS_REVOKED puts "certificate has been revoked at #{single_response.revocation_time}" when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN puts 'responder doesn't know about the certificate' end
Flags for regular expression and match last line nodes.
Prism
parses deterministically for the same input. This provides a nice property that is exposed through the node_id API on nodes. Effectively this means that for the same input, these values will remain consistent every time the source is parsed. This means we can reparse the source same with a node_id value and find the exact same node again.
The Relocation
module provides an API around this property. It allows you to “save” nodes and locations using a minimal amount of memory (just the node_id and a field identifier) and then reify them later.
Mixin methods for local and remote Gem::Command
options.
A StoreContext
is used while validating a single certificate and holds the status involved.
Immutable and read-only representation of a timestamp token info from a Response
.
Used to generate a Response
from scratch.
Please bear in mind that the implementation will always apply and prefer the policy object identifier given in the request over the default policy id specified in the Factory
. As a consequence, default_policy_id
will only be applied if no Request#policy_id
was given. But this also means that one needs to check the policy identifier in the request manually before creating the Response
, e.g. to check whether it complies to a specific set of acceptable policies.
There exists also the possibility to add certificates (instances of OpenSSL::X509::Certificate
) besides the timestamping certificate that will be included in the resulting timestamp token if Request#cert_requested?
is true
. Ideally, one would also include any intermediate certificates (the root certificate can be left out - in order to trust it any verifying party will have to be in its possession anyway). This simplifies validation of the timestamp since these intermediate certificates are “already there” and need not be passed as external parameters to Response#verify
anymore, thus minimizing external resources needed for verification.
Assume we received a timestamp request that has set Request#policy_id
to nil
and Request#cert_requested?
to true. The raw request bytes are stored in a variable called req_raw
. We’d still like to integrate the necessary intermediate certificates (in inter1.cer
and inter2.cer
) to simplify validation of the resulting Response
. ts.p12
is a PKCS#12-compatible file including the private key and the timestamping certificate.
req = OpenSSL::Timestamp::Request.new(raw_bytes) p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd') inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer')) inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer')) fac = OpenSSL::Timestamp::Factory.new fac.gen_time = Time.now fac.serial_number = 1 fac.allowed_digests = ["sha256", "sha384", "sha512"] #needed because the Request contained no policy identifier fac.default_policy_id = '1.2.3.4.5' fac.additional_certificates = [ inter1, inter2 ] timestamp = fac.create_timestamp(p12.key, p12.certificate, req)
default_policy_id
Request#policy_id
will always be preferred over this if present in the Request
, only if Request#policy_id
is nil default_policy will be used. If none of both is present, a TimestampError
will be raised when trying to create a Response
.
call-seq:
factory.default_policy_id = "string" -> string factory.default_policy_id -> string or nil
serial_number
Sets or retrieves the serial number to be used for timestamp creation. Must be present for timestamp creation.
call-seq:
factory.serial_number = number -> number factory.serial_number -> number or nil
gen_time
Sets or retrieves the Time
value to be used in the Response
. Must be present for timestamp creation.
call-seq:
factory.gen_time = Time -> Time factory.gen_time -> Time or nil
additional_certs
Sets or retrieves additional certificates apart from the timestamp certificate (e.g. intermediate certificates) to be added to the Response
. Must be an Array
of OpenSSL::X509::Certificate
.
call-seq:
factory.additional_certs = [cert1, cert2] -> [ cert1, cert2 ] factory.additional_certs -> array or nil
allowed_digests
Sets or retrieves the digest algorithms that the factory is allowed create timestamps for. Known vulnerable or weak algorithms should not be allowed where possible. Must be an Array
of String
or OpenSSL::Digest
subclass instances.
call-seq:
factory.allowed_digests = ["sha1", OpenSSL::Digest.new('SHA256').new] -> [ "sha1", OpenSSL::Digest) ] factory.allowed_digests -> array or nil
The X509
certificate store holds trusted CA certificates used to verify peer certificates.
The easiest way to create a useful certificate store is:
cert_store = OpenSSL::X509::Store.new cert_store.set_default_paths
This will use your system’s built-in certificates.
If your system does not have a default set of certificates you can obtain a set extracted from Mozilla CA certificate store by cURL maintainers here: curl.haxx.se/docs/caextract.html (You may wish to use the firefox-db2pem.sh script to extract the certificates from a local install to avoid man-in-the-middle attacks.)
After downloading or generating a cacert.pem from the above link you can create a certificate store from the pem file like this:
cert_store = OpenSSL::X509::Store.new cert_store.add_file 'cacert.pem'
The certificate store can be used with an SSLSocket like this:
ssl_context = OpenSSL::SSL::SSLContext.new ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER ssl_context.cert_store = cert_store tcp_socket = TCPSocket.open 'example.com', 443 ssl_socket = OpenSSL::SSL::SSLSocket.new tcp_socket, ssl_context
This class walks a YAML
AST, converting each node to Ruby
File-based session storage class.
Implements session storage as a flat file of ‘key=value’ values. This storage type only works directly with String
values; the user is responsible for converting other types to Strings when storing and from Strings when retrieving.
In-memory session storage class.
Implements session storage as a global in-memory hash. Session
data will only persist for as long as the Ruby interpreter instance does.
Dummy session storage class.
Implements session storage place holder. No actual storage will be done.