Welcome to mirror list, hosted at ThFree Co, Russian Federation.

certificate.rb « x509 « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 752f3c6b0049ab9c6beeb3a5c3001f8c8edf2604 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# frozen_string_literal: true

module Gitlab
  module X509
    class Certificate
      CERT_REGEX = /-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/.freeze

      attr_reader :key, :cert, :ca_certs

      def key_string
        key.to_s
      end

      def cert_string
        cert.to_pem
      end

      def ca_certs_string
        ca_certs.map(&:to_pem).join('\n') unless ca_certs.blank?
      end

      class << self
        include ::Gitlab::Utils::StrongMemoize
      end

      def self.from_strings(key_string, cert_string, ca_certs_string = nil)
        key = OpenSSL::PKey::RSA.new(key_string)
        cert = OpenSSL::X509::Certificate.new(cert_string)
        ca_certs = load_ca_certs_bundle(ca_certs_string)

        new(key, cert, ca_certs)
      end

      def self.from_files(key_path, cert_path, ca_certs_path = nil)
        ca_certs_string = File.read(ca_certs_path) if ca_certs_path

        from_strings(File.read(key_path), File.read(cert_path), ca_certs_string)
      end

      # Returns all top-level, readable files in the default CA cert directory
      def self.ca_certs_paths
        cert_paths = Dir["#{OpenSSL::X509::DEFAULT_CERT_DIR}/*"].select do |path|
          !File.directory?(path) && File.readable?(path)
        end
        cert_paths << OpenSSL::X509::DEFAULT_CERT_FILE if File.exist? OpenSSL::X509::DEFAULT_CERT_FILE
        cert_paths
      end

      # Returns a concatenated array of Strings, each being a PEM-coded CA certificate.
      def self.ca_certs_bundle
        strong_memoize(:ca_certs_bundle) do
          ca_certs_paths.flat_map do |cert_file|
            load_ca_certs_bundle(File.read(cert_file))
          rescue OpenSSL::OpenSSLError => e
            Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e, cert_file: cert_file)
          end.uniq.join("\n")
        end
      end

      def self.reset_ca_certs_bundle
        clear_memoization(:ca_certs_bundle)
      end

      # Returns an array of OpenSSL::X509::Certificate objects, empty array if none found
      #
      # Ruby OpenSSL::X509::Certificate.new will only load the first
      # certificate if a bundle is presented, this allows to parse multiple certs
      # in the same file
      def self.load_ca_certs_bundle(ca_certs_string)
        return [] unless ca_certs_string

        ca_certs_string.scan(CERT_REGEX).map do |ca_cert_string|
          OpenSSL::X509::Certificate.new(ca_cert_string)
        end
      end

      def initialize(key, cert, ca_certs = nil)
        @key = key
        @cert = cert
        @ca_certs = ca_certs
      end
    end
  end
end