certificate_spec.rb 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe SecureMailing::SMIME::Certificate do
  4. def fixture(name)
  5. Rails.root.join('spec/fixtures/files/smime', "#{name}.crt").read.strip
  6. end
  7. describe '#parse' do
  8. context 'when certificate is valid' do
  9. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  10. it 'returns a certificate' do
  11. expect(described_class.parse(certificate)).to be_a(described_class)
  12. end
  13. end
  14. context 'when certificate is invalid' do
  15. let(:certificate) { 'invalid' }
  16. it 'raises an error' do
  17. message = 'The certificate is not valid for S/MIME usage. Please check the certificate format.'
  18. expect { described_class.parse(certificate) }.to raise_error(Exceptions::UnprocessableEntity, message)
  19. end
  20. end
  21. end
  22. describe '#new' do
  23. context 'when certificate is valid' do
  24. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  25. it 'returns a certificate' do
  26. expect(described_class.new(certificate)).to be_a(described_class)
  27. .and have_attributes(
  28. 'email_addresses' => Array,
  29. 'fingerprint' => String,
  30. 'issuer_hash' => String,
  31. 'subject_hash' => String,
  32. 'uid' => String
  33. )
  34. end
  35. end
  36. context 'when certificate is invalid' do
  37. let(:certificate) { 'invalid' }
  38. it 'raises an error' do
  39. expect { described_class.new(certificate) }.to raise_error(OpenSSL::X509::CertificateError)
  40. end
  41. end
  42. end
  43. describe '.ca?' do
  44. context 'when certificate is a CA' do
  45. let(:certificate) { fixture('RootCA') }
  46. it 'returns true' do
  47. expect(described_class.new(certificate)).to be_ca
  48. end
  49. end
  50. context 'when certificate is not a CA' do
  51. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  52. it 'returns false' do
  53. expect(described_class.new(certificate)).not_to be_ca
  54. end
  55. end
  56. end
  57. describe '.rsa?' do
  58. context 'when certificate has RSA key' do
  59. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  60. it 'returns true' do
  61. expect(described_class.new(certificate)).to be_rsa
  62. end
  63. end
  64. context 'when certificate has no RSA key' do
  65. let(:certificate) { fixture('alice@acme.corp+sign+encrypt+ec') }
  66. it 'returns false' do
  67. expect(described_class.new(certificate)).not_to be_rsa
  68. end
  69. end
  70. end
  71. describe '.ec?' do
  72. context 'when certificate has EC key' do
  73. let(:certificate) { fixture('alice@acme.corp+sign+encrypt+ec') }
  74. it 'returns true' do
  75. expect(described_class.new(certificate)).to be_ec
  76. end
  77. end
  78. context 'when certificate has no EC key' do
  79. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  80. it 'returns false' do
  81. expect(described_class.new(certificate)).not_to be_ec
  82. end
  83. end
  84. end
  85. describe '.effective?' do
  86. context 'when certificate is already valid (not before date is in past)' do
  87. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  88. it 'returns true' do
  89. expect(described_class.new(certificate)).to be_effective
  90. end
  91. end
  92. context 'when certificate is not yet valid (not before date is in future)' do
  93. let(:certificate) { fixture('alice@acme.corp+sign+encrypt+future') }
  94. it 'returns false' do
  95. expect(described_class.new(certificate)).not_to be_effective
  96. end
  97. end
  98. end
  99. describe '.expired?' do
  100. context 'when certificate is expired (not after date is in past)' do
  101. let(:certificate) { fixture('alice@acme.corp+sign+encrypt+expired') }
  102. it 'returns true' do
  103. expect(described_class.new(certificate)).to be_expired
  104. end
  105. end
  106. context 'when certificate is not expired (not after date is in future)' do
  107. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  108. it 'returns false' do
  109. expect(described_class.new(certificate)).not_to be_expired
  110. end
  111. end
  112. end
  113. describe '.signature?' do
  114. context 'when certificate is usable for signing' do
  115. let(:certificate) { fixture('alice@acme.corp+sign') }
  116. it 'returns true' do
  117. expect(described_class.new(certificate)).to be_signature
  118. end
  119. end
  120. context 'when certificate is not usable for signing' do
  121. let(:certificate) { fixture('alice@acme.corp+encrypt') }
  122. it 'returns false' do
  123. expect(described_class.new(certificate)).not_to be_signature
  124. end
  125. end
  126. context 'when certificate is usable for signing and encrypting' do
  127. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  128. it 'returns true' do
  129. expect(described_class.new(certificate)).to be_signature
  130. end
  131. end
  132. end
  133. describe '.encryption?' do
  134. context 'when certificate is usable for encrypting' do
  135. let(:certificate) { fixture('alice@acme.corp+encrypt') }
  136. it 'returns true' do
  137. expect(described_class.new(certificate)).to be_encryption
  138. end
  139. end
  140. context 'when certificate is not usable for encrypting' do
  141. let(:certificate) { fixture('alice@acme.corp+sign') }
  142. it 'returns false' do
  143. expect(described_class.new(certificate)).not_to be_encryption
  144. end
  145. end
  146. context 'when certificate is usable for signing and encrypting' do
  147. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  148. it 'returns true' do
  149. expect(described_class.new(certificate)).to be_encryption
  150. end
  151. end
  152. end
  153. describe '.applicable?' do
  154. context 'when certificate has valid extended key usage (E-mail Protection)' do
  155. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  156. it 'returns true' do
  157. expect(described_class.new(certificate)).to be_applicable
  158. end
  159. end
  160. context 'when certificate has no valid extended key usage (E-mail Protection)' do
  161. let(:certificate) { fixture('zammad.com') }
  162. it 'returns false' do
  163. expect(described_class.new(certificate)).not_to be_applicable
  164. end
  165. end
  166. end
  167. describe '.usable?' do
  168. context 'when certificate is effective and not expired' do
  169. let(:certificate) { fixture('alice@acme.corp+sign+encrypt') }
  170. it 'returns true' do
  171. expect(described_class.new(certificate)).to be_usable
  172. end
  173. end
  174. context 'when certificate is expired' do
  175. let(:certificate) { fixture('alice@acme.corp+sign+encrypt+expired') }
  176. it 'returns false' do
  177. expect(described_class.new(certificate)).not_to be_usable
  178. end
  179. end
  180. context 'when certificate is not yet effective' do
  181. let(:certificate) { fixture('alice@acme.corp+sign+encrypt+future') }
  182. it 'returns false' do
  183. expect(described_class.new(certificate)).not_to be_usable
  184. end
  185. end
  186. end
  187. describe '.valid_smime_certificate?' do
  188. context 'when certificate is issued for SMIME usage' do
  189. let(:certificate) { fixture('alice@acme.corp+sign+encrypt+expired') }
  190. it 'returns true' do
  191. expect(described_class.new(certificate)).to be_valid_smime_certificate
  192. end
  193. end
  194. context 'when certificate is not issued for SMIME usage' do
  195. let(:certificate) { fixture('zammad.com') }
  196. it 'returns false' do
  197. expect(described_class.new(certificate)).not_to be_valid_smime_certificate
  198. end
  199. end
  200. end
  201. describe '.valid_smime_certificate!' do
  202. context 'when certificate is issued for SMIME usage' do
  203. let(:certificate) { fixture('alice@acme.corp+sign+encrypt+expired') }
  204. it 'raises no exception' do
  205. expect { described_class.new(certificate).valid_smime_certificate! }.not_to raise_error
  206. end
  207. end
  208. context 'when certificate is not issued for SMIME usage' do
  209. let(:certificate) { fixture('zammad.com') }
  210. it 'returns false' do
  211. message = 'The certificate is not valid for S/MIME usage. Please check the key usage, subject alternative name and public key cryptographic algorithm.'
  212. expect { described_class.new(certificate).valid_smime_certificate! }.to raise_error(Exceptions::UnprocessableEntity, message)
  213. end
  214. end
  215. end
  216. end