Skip to content

Commit 093858a

Browse files
committed
Merge branch 'ecdsa_pages_certificates' into 'master'
Allow to load ECDSA certificates for pages domains See merge request gitlab-org/gitlab-ce!32393
2 parents 7920ff1 + 8c3d070 commit 093858a

File tree

7 files changed

+198
-4
lines changed

7 files changed

+198
-4
lines changed

app/models/pages_domain.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class PagesDomain < ApplicationRecord
1717
validates :certificate, certificate: true, if: ->(domain) { domain.certificate.present? }
1818
validates :key, presence: { message: 'must be present if HTTPS-only is enabled' },
1919
if: :certificate_should_be_present?
20-
validates :key, certificate_key: true, if: ->(domain) { domain.key.present? }
20+
validates :key, certificate_key: true, named_ecdsa_key: true, if: ->(domain) { domain.key.present? }
2121
validates :verification_code, presence: true, allow_blank: false
2222

2323
validate :validate_pages_domain
@@ -247,7 +247,7 @@ def x509
247247
def pkey
248248
return unless key
249249

250-
@pkey ||= OpenSSL::PKey::RSA.new(key)
250+
@pkey ||= OpenSSL::PKey.read(key)
251251
rescue OpenSSL::PKey::PKeyError, OpenSSL::Cipher::CipherError
252252
nil
253253
end

app/validators/certificate_key_validator.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
# UrlValidator
3+
# CertificateKeyValidator
44
#
55
# Custom validator for private keys.
66
#
@@ -20,7 +20,7 @@ def validate_each(record, attribute, value)
2020
def valid_private_key_pem?(value)
2121
return false unless value
2222

23-
pkey = OpenSSL::PKey::RSA.new(value)
23+
pkey = OpenSSL::PKey.read(value)
2424
pkey.private?
2525
rescue OpenSSL::PKey::PKeyError
2626
false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
# NamedEcdsaKeyValidator
4+
#
5+
# Custom validator for ecdsa private keys.
6+
# Golang currently doesn't support explicit curves for ECDSA certificates
7+
# This validator checks if curve is set by name, not by parameters
8+
#
9+
# class Project < ActiveRecord::Base
10+
# validates :certificate_key, named_ecdsa_key: true
11+
# end
12+
#
13+
class NamedEcdsaKeyValidator < ActiveModel::EachValidator
14+
def validate_each(record, attribute, value)
15+
if explicit_ec?(value)
16+
record.errors.add(attribute, "ECDSA keys with explicit curves are not supported")
17+
end
18+
end
19+
20+
private
21+
22+
UNNAMED_CURVE = "UNDEF"
23+
24+
def explicit_ec?(value)
25+
return false unless value
26+
27+
pkey = OpenSSL::PKey.read(value)
28+
return false unless pkey.is_a?(OpenSSL::PKey::EC)
29+
30+
pkey.group.curve_name == UNNAMED_CURVE
31+
rescue OpenSSL::PKey::PKeyError
32+
false
33+
end
34+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
title: Allow ECDSA certificates for pages domains
3+
merge_request: 32393
4+
author:
5+
type: added

spec/factories/pages_domains.rb

+83
Original file line numberDiff line numberDiff line change
@@ -271,5 +271,88 @@
271271
auto_ssl_enabled { true }
272272
certificate_source { :gitlab_provided }
273273
end
274+
275+
trait :explicit_ecdsa do
276+
certificate '-----BEGIN CERTIFICATE-----
277+
MIID1zCCAzkCCQDatOIwBlktwjAKBggqhkjOPQQDAjBPMQswCQYDVQQGEwJVUzEL
278+
MAkGA1UECAwCTlkxCzAJBgNVBAcMAk5ZMQswCQYDVQQLDAJJVDEZMBcGA1UEAwwQ
279+
dGVzdC1jZXJ0aWZpY2F0ZTAeFw0xOTA4MjkxMTE1NDBaFw0yMTA4MjgxMTE1NDBa
280+
ME8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTELMAkGA1UEBwwCTlkxCzAJBgNV
281+
BAsMAklUMRkwFwYDVQQDDBB0ZXN0LWNlcnRpZmljYXRlMIICXDCCAc8GByqGSM49
282+
AgEwggHCAgEBME0GByqGSM49AQECQgH/////////////////////////////////
283+
/////////////////////////////////////////////////////zCBngRCAf//
284+
////////////////////////////////////////////////////////////////
285+
///////////////////8BEFRlT65YY4cmh+SmiGgtoVA7qLacluZsxXzuLSJkY7x
286+
CeFWGTlR7H6TexZSwL07sb8HNXPfiD0sNPHvRR/Ua1A/AAMVANCeiAApHLhTlsxn
287+
FzkyhKqg2mS6BIGFBADGhY4GtwQE6c2ePstmI5W0QpxkgTkFP7Uh+CivYGtNPbqh
288+
S1537+dZKP4dwSei/6jeM0izwYVqQpv5fn4xwuW9ZgEYOSlqeJo7wARcil+0LH0b
289+
2Zj1RElXm0RoF6+9Fyc+ZiyX7nKZXvQmQMVQuQE/rQdhNTxwhqJywkCIvpR2n9Fm
290+
UAJCAf//////////////////////////////////////////+lGGh4O/L5Zrf8wB
291+
SPcJpdA7tcm4iZxHrrtvtx6ROGQJAgEBA4GGAAQBVG/4c/hgl36toHj+eGL4pqv7
292+
l7M+ZKQJ4vz0Y9E6xIx+gvfVaZ58krmbBAP53ikwneQbFdcvw3L/ACPEib/qWjkB
293+
ogykguy3OwHtKLYNnDWIsfiLumEjElhcBMZVXiXhb5txf11uXAWn5n6Qhey5YKPM
294+
NjLLqDqaG19efCLCd21A0TcwCgYIKoZIzj0EAwIDgYsAMIGHAkEm68kYFVnN1c2N
295+
OjSJpIDdFWGVYJHyMDI5WgQyhm4hAioXJ0T22Zab8Wmq+hBYRJNcHoaV894blfqR
296+
V3ZJgam8EQJCAcnPpJQ0IqoT1pAQkaL3+Ka8ZaaCd6/8RnoDtGvWljisuyH65SRu
297+
kmYv87bZe1KqOZDoaDBdfVsoxcGbik19lBPV
298+
-----END CERTIFICATE-----'
299+
300+
key '-----BEGIN EC PARAMETERS-----
301+
MIIBwgIBATBNBgcqhkjOPQEBAkIB////////////////////////////////////
302+
//////////////////////////////////////////////////8wgZ4EQgH/////
303+
////////////////////////////////////////////////////////////////
304+
/////////////////ARBUZU+uWGOHJofkpohoLaFQO6i2nJbmbMV87i0iZGO8Qnh
305+
Vhk5Uex+k3sWUsC9O7G/BzVz34g9LDTx70Uf1GtQPwADFQDQnogAKRy4U5bMZxc5
306+
MoSqoNpkugSBhQQAxoWOBrcEBOnNnj7LZiOVtEKcZIE5BT+1Ifgor2BrTT26oUte
307+
d+/nWSj+HcEnov+o3jNIs8GFakKb+X5+McLlvWYBGDkpaniaO8AEXIpftCx9G9mY
308+
9URJV5tEaBevvRcnPmYsl+5ymV70JkDFULkBP60HYTU8cIaicsJAiL6Udp/RZlAC
309+
QgH///////////////////////////////////////////pRhoeDvy+Wa3/MAUj3
310+
CaXQO7XJuImcR667b7cekThkCQIBAQ==
311+
-----END EC PARAMETERS-----
312+
-----BEGIN EC PRIVATE KEY-----
313+
MIICnQIBAQRCAZZRG4FJO+OK29ygycrNzjxQDB+dp+QPo1Pk6RAl5PcraohyhFnI
314+
MGUL4ba1efZUxCbAWxjVRSi7QEUNYCCdUPAtoIIBxjCCAcICAQEwTQYHKoZIzj0B
315+
AQJCAf//////////////////////////////////////////////////////////
316+
////////////////////////////MIGeBEIB////////////////////////////
317+
//////////////////////////////////////////////////////////wEQVGV
318+
PrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ4VYZOVHsfpN7FlLAvTuxvwc1
319+
c9+IPSw08e9FH9RrUD8AAxUA0J6IACkcuFOWzGcXOTKEqqDaZLoEgYUEAMaFjga3
320+
BATpzZ4+y2YjlbRCnGSBOQU/tSH4KK9ga009uqFLXnfv51ko/h3BJ6L/qN4zSLPB
321+
hWpCm/l+fjHC5b1mARg5KWp4mjvABFyKX7QsfRvZmPVESVebRGgXr70XJz5mLJfu
322+
cple9CZAxVC5AT+tB2E1PHCGonLCQIi+lHaf0WZQAkIB////////////////////
323+
///////////////////////6UYaHg78vlmt/zAFI9wml0Du1ybiJnEeuu2+3HpE4
324+
ZAkCAQGhgYkDgYYABAFUb/hz+GCXfq2geP54Yvimq/uXsz5kpAni/PRj0TrEjH6C
325+
99VpnnySuZsEA/neKTCd5BsV1y/Dcv8AI8SJv+paOQGiDKSC7Lc7Ae0otg2cNYix
326+
+Iu6YSMSWFwExlVeJeFvm3F/XW5cBafmfpCF7Llgo8w2MsuoOpobX158IsJ3bUDR
327+
Nw==
328+
-----END EC PRIVATE KEY-----'
329+
end
330+
331+
trait :ecdsa do
332+
certificate '-----BEGIN CERTIFICATE-----
333+
MIIB8zCCAVUCCQCGKuPQ6SBxUTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJVUzEL
334+
MAkGA1UECAwCVVMxCzAJBgNVBAcMAlVTMRUwEwYDVQQDDAxzaHVzaGxpbi5kZXYw
335+
HhcNMTkwOTAyMDkyMDUxWhcNMjEwOTAxMDkyMDUxWjA+MQswCQYDVQQGEwJVUzEL
336+
MAkGA1UECAwCVVMxCzAJBgNVBAcMAlVTMRUwEwYDVQQDDAxzaHVzaGxpbi5kZXYw
337+
gZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAH9Jd7ZWnTasgltZRbIMreihycOh/G4
338+
TXpkp8tTtEsuD+sh8au3Jywsi89RSZ6vgVoCY7//DQ2vamYnyBZqbL+cTQBsQ7wD
339+
UEaSyP0R3P4b6Ox347pYzXwSdSOra9Cm4TMQe+prVMesxulqIm7G7CTI+9J8LHlJ
340+
z0wUDQz/o+tUSYwv6zAKBggqhkjOPQQDAgOBiwAwgYcCQUOlTnn2QP/uYSh1dUSl
341+
R9WYUg5+PQMg7kS+4K/5+5gonWCvaMcP+2P7hltUcvq41l3uMKKCZRU/x60/FMHc
342+
1ZXdAkIBuVtm9RJXziNOKS4TcpH9os/FuREW8YQlpec58LDZdlivcHnikHZ4LCri
343+
T7zu3VY6Rq+V/IKpsQwQjmoTJ0IpCM8=
344+
-----END CERTIFICATE-----'
345+
346+
key '-----BEGIN EC PARAMETERS-----
347+
BgUrgQQAIw==
348+
-----END EC PARAMETERS-----
349+
-----BEGIN EC PRIVATE KEY-----
350+
MIHbAgEBBEFa72+eREW25IHbke0TiWFdW1R1ad9Nyqaz7CDtv5Kqdgd6Kcl8V2az
351+
Lr6z1PS+JSERWzRP+fps7kdFRrtqy/ECpKAHBgUrgQQAI6GBiQOBhgAEAf0l3tla
352+
dNqyCW1lFsgyt6KHJw6H8bhNemSny1O0Sy4P6yHxq7cnLCyLz1FJnq+BWgJjv/8N
353+
Da9qZifIFmpsv5xNAGxDvANQRpLI/RHc/hvo7HfjuljNfBJ1I6tr0KbhMxB76mtU
354+
x6zG6WoibsbsJMj70nwseUnPTBQNDP+j61RJjC/r
355+
-----END EC PRIVATE KEY-----'
356+
end
274357
end
275358
end

spec/models/pages_domain_spec.rb

+18
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,24 @@
151151
end
152152
end
153153
end
154+
155+
context 'with ecdsa certificate' do
156+
it "is valid" do
157+
domain = build(:pages_domain, :ecdsa)
158+
159+
expect(domain).to be_valid
160+
end
161+
162+
context 'when curve is set explicitly by parameters' do
163+
it 'adds errors to private key' do
164+
domain = build(:pages_domain, :explicit_ecdsa)
165+
166+
expect(domain).to be_invalid
167+
168+
expect(domain.errors[:key]).not_to be_empty
169+
end
170+
end
171+
end
154172
end
155173

156174
describe 'validations' do
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
describe NamedEcdsaKeyValidator do
6+
let(:validator) { described_class.new(attributes: [:key]) }
7+
let!(:domain) { build(:pages_domain) }
8+
9+
subject { validator.validate_each(domain, :key, value) }
10+
11+
context 'with empty value' do
12+
let(:value) { nil }
13+
14+
it 'does not add any error if value is empty' do
15+
subject
16+
17+
expect(domain.errors).to be_empty
18+
end
19+
end
20+
21+
shared_examples 'does not add any error' do
22+
it 'does not add any error' do
23+
expect(value).to be_present
24+
25+
subject
26+
27+
expect(domain.errors).to be_empty
28+
end
29+
end
30+
31+
context 'when key is not EC' do
32+
let(:value) { attributes_for(:pages_domain)[:key] }
33+
34+
include_examples 'does not add any error'
35+
end
36+
37+
context 'with ECDSA certificate with named curve' do
38+
let(:value) { attributes_for(:pages_domain, :ecdsa)[:key] }
39+
40+
include_examples 'does not add any error'
41+
end
42+
43+
context 'with ECDSA certificate with explicit curve params' do
44+
let(:value) { attributes_for(:pages_domain, :explicit_ecdsa)[:key] }
45+
46+
it 'adds errors' do
47+
expect(value).to be_present
48+
49+
subject
50+
51+
expect(domain.errors[:key]).not_to be_empty
52+
end
53+
end
54+
end

0 commit comments

Comments
 (0)