1require 'rubygems/test_case' 2require 'rubygems/security' 3require 'rubygems/fix_openssl_warnings' if RUBY_VERSION < "1.9" 4 5class TestGemSecurity < Gem::TestCase 6 7 CHILD_KEY = load_key 'child' 8 9 ALTERNATE_CERT = load_cert 'child' 10 CHILD_CERT = load_cert 'child' 11 EXPIRED_CERT = load_cert 'expired' 12 13 def setup 14 super 15 16 @SEC = Gem::Security 17 end 18 19 def test_class_create_cert 20 name = PUBLIC_CERT.subject 21 key = PRIVATE_KEY 22 23 cert = @SEC.create_cert name, key, 60, Gem::Security::EXTENSIONS, 5 24 25 assert_kind_of OpenSSL::X509::Certificate, cert 26 27 assert_equal 2, cert.version 28 assert_equal 5, cert.serial 29 assert_equal key.public_key.to_pem, cert.public_key.to_pem 30 assert_in_delta Time.now, cert.not_before, 10 31 assert_in_delta Time.now + 60, cert.not_after, 10 32 assert_equal name.to_s, cert.subject.to_s 33 34 assert_equal 3, cert.extensions.length, 35 cert.extensions.map { |e| e.to_a.first } 36 37 constraints = cert.extensions.find { |ext| ext.oid == 'basicConstraints' } 38 assert_equal 'CA:FALSE', constraints.value 39 40 key_usage = cert.extensions.find { |ext| ext.oid == 'keyUsage' } 41 assert_equal 'Digital Signature, Key Encipherment, Data Encipherment', 42 key_usage.value 43 44 key_ident = cert.extensions.find { |ext| ext.oid == 'subjectKeyIdentifier' } 45 assert_equal 59, key_ident.value.length 46 assert_equal '5F:43:6E:F6:9A:8E:45:25:E9:22:E3:7D:37:5E:A4:D5:36:02:85:1B', 47 key_ident.value 48 49 assert_equal '', cert.issuer.to_s 50 assert_equal name.to_s, cert.subject.to_s 51 end 52 53 def test_class_create_cert_self_signed 54 subject = PUBLIC_CERT.subject 55 56 cert = @SEC.create_cert_self_signed subject, PRIVATE_KEY, 60 57 58 assert_equal '/CN=nobody/DC=example', cert.issuer.to_s 59 end 60 61 def test_class_create_cert_email 62 email = 'nobody@example' 63 name = PUBLIC_CERT.subject 64 key = PRIVATE_KEY 65 66 cert = @SEC.create_cert_email email, key, 60 67 68 assert_kind_of OpenSSL::X509::Certificate, cert 69 70 assert_equal 2, cert.version 71 assert_equal 1, cert.serial 72 assert_equal key.public_key.to_pem, cert.public_key.to_pem 73 assert_in_delta Time.now, cert.not_before, 10 74 assert_in_delta Time.now + 60, cert.not_after, 10 75 assert_equal name.to_s, cert.subject.to_s 76 assert_equal name.to_s, cert.issuer.to_s 77 78 assert_equal 5, cert.extensions.length, 79 cert.extensions.map { |e| e.to_a.first } 80 81 constraints = cert.extensions.find { |ext| ext.oid == 'subjectAltName' } 82 assert_equal 'email:nobody@example', constraints.value 83 84 constraints = cert.extensions.find { |ext| ext.oid == 'basicConstraints' } 85 assert_equal 'CA:FALSE', constraints.value 86 87 key_usage = cert.extensions.find { |ext| ext.oid == 'keyUsage' } 88 assert_equal 'Digital Signature, Key Encipherment, Data Encipherment', 89 key_usage.value 90 91 key_ident = cert.extensions.find { |ext| ext.oid == 'subjectKeyIdentifier' } 92 assert_equal 59, key_ident.value.length 93 assert_equal '5F:43:6E:F6:9A:8E:45:25:E9:22:E3:7D:37:5E:A4:D5:36:02:85:1B', 94 key_ident.value 95 end 96 97 def test_class_create_key 98 key = @SEC.create_key 256 99 100 assert_kind_of OpenSSL::PKey::RSA, key 101 end 102 103 def test_class_email_to_name 104 assert_equal '/CN=nobody/DC=example', 105 @SEC.email_to_name('nobody@example').to_s 106 107 assert_equal '/CN=nobody/DC=example/DC=com', 108 @SEC.email_to_name('nobody@example.com').to_s 109 110 assert_equal '/CN=no.body/DC=example', 111 @SEC.email_to_name('no.body@example').to_s 112 113 assert_equal '/CN=no_body/DC=example', 114 @SEC.email_to_name('no+body@example').to_s 115 end 116 117 def test_class_re_sign 118 re_signed = Gem::Security.re_sign EXPIRED_CERT, PRIVATE_KEY, 60 119 120 assert_in_delta Time.now, re_signed.not_before, 10 121 assert_in_delta Time.now + 60, re_signed.not_after, 10 122 assert_equal EXPIRED_CERT.serial + 1, re_signed.serial 123 124 assert re_signed.verify PUBLIC_KEY 125 end 126 127 def test_class_re_sign_not_self_signed 128 e = assert_raises Gem::Security::Exception do 129 Gem::Security.re_sign CHILD_CERT, CHILD_KEY 130 end 131 132 child_alt_name = CHILD_CERT.extensions.find do |extension| 133 extension.oid == 'subjectAltName' 134 end 135 136 assert_equal "#{child_alt_name.value} is not self-signed, contact " + 137 "#{ALTERNATE_CERT.issuer} to obtain a valid certificate", 138 e.message 139 end 140 141 def test_class_re_sign_wrong_key 142 e = assert_raises Gem::Security::Exception do 143 Gem::Security.re_sign ALTERNATE_CERT, PRIVATE_KEY 144 end 145 146 assert_equal "incorrect signing key for re-signing " + 147 "#{ALTERNATE_CERT.subject}", 148 e.message 149 end 150 151 def test_class_reset 152 trust_dir = @SEC.trust_dir 153 154 @SEC.reset 155 156 refute_equal trust_dir, @SEC.trust_dir 157 end 158 159 def test_class_sign 160 issuer = PUBLIC_CERT.subject 161 signee = OpenSSL::X509::Name.parse "/CN=signee/DC=example" 162 163 key = PRIVATE_KEY 164 cert = OpenSSL::X509::Certificate.new 165 cert.subject = signee 166 167 cert.subject = signee 168 cert.public_key = key.public_key 169 170 signed = @SEC.sign cert, key, PUBLIC_CERT, 60 171 172 assert_equal key.public_key.to_pem, signed.public_key.to_pem 173 assert_equal signee.to_s, signed.subject.to_s 174 assert_equal issuer.to_s, signed.issuer.to_s 175 176 assert_in_delta Time.now, signed.not_before, 10 177 assert_in_delta Time.now + 60, signed.not_after, 10 178 179 assert_equal 4, signed.extensions.length, 180 signed.extensions.map { |e| e.to_a.first } 181 182 constraints = signed.extensions.find { |ext| ext.oid == 'issuerAltName' } 183 assert_equal 'email:nobody@example', constraints.value, 'issuerAltName' 184 185 constraints = signed.extensions.find { |ext| ext.oid == 'basicConstraints' } 186 assert_equal 'CA:FALSE', constraints.value 187 188 key_usage = signed.extensions.find { |ext| ext.oid == 'keyUsage' } 189 assert_equal 'Digital Signature, Key Encipherment, Data Encipherment', 190 key_usage.value 191 192 key_ident = 193 signed.extensions.find { |ext| ext.oid == 'subjectKeyIdentifier' } 194 assert_equal 59, key_ident.value.length 195 assert_equal '5F:43:6E:F6:9A:8E:45:25:E9:22:E3:7D:37:5E:A4:D5:36:02:85:1B', 196 key_ident.value 197 198 assert signed.verify key 199 end 200 201 def test_class_sign_AltName 202 issuer = PUBLIC_CERT.subject 203 signee = OpenSSL::X509::Name.parse "/CN=signee/DC=example" 204 205 cert = @SEC.create_cert_email 'signee@example', PRIVATE_KEY 206 207 signed = @SEC.sign cert, PRIVATE_KEY, PUBLIC_CERT, 60 208 209 assert_equal PUBLIC_KEY.to_pem, signed.public_key.to_pem 210 assert_equal signee.to_s, signed.subject.to_s 211 assert_equal issuer.to_s, signed.issuer.to_s 212 213 assert_in_delta Time.now, signed.not_before, 10 214 assert_in_delta Time.now + 60, signed.not_after, 10 215 216 assert_equal 5, signed.extensions.length, 217 signed.extensions.map { |e| e.to_a.first } 218 219 constraints = signed.extensions.find { |ext| ext.oid == 'issuerAltName' } 220 assert_equal 'email:nobody@example', constraints.value, 'issuerAltName' 221 222 constraints = signed.extensions.find { |ext| ext.oid == 'subjectAltName' } 223 assert_equal 'email:signee@example', constraints.value, 'subjectAltName' 224 225 constraints = signed.extensions.find { |ext| ext.oid == 'basicConstraints' } 226 assert_equal 'CA:FALSE', constraints.value 227 228 key_usage = signed.extensions.find { |ext| ext.oid == 'keyUsage' } 229 assert_equal 'Digital Signature, Key Encipherment, Data Encipherment', 230 key_usage.value 231 232 key_ident = 233 signed.extensions.find { |ext| ext.oid == 'subjectKeyIdentifier' } 234 assert_equal 59, key_ident.value.length 235 assert_equal '5F:43:6E:F6:9A:8E:45:25:E9:22:E3:7D:37:5E:A4:D5:36:02:85:1B', 236 key_ident.value 237 238 assert signed.verify PUBLIC_KEY 239 end 240 241 def test_class_trust_dir 242 trust_dir = @SEC.trust_dir 243 244 expected = File.join Gem.user_home, '.gem/trust' 245 246 assert_equal expected, trust_dir.dir 247 end 248 249end 250 251