Fixes #1961 - S/MIME integration.

This commit is contained in:
Thorsten Eckel 2020-06-02 13:01:16 +02:00
parent d64ea29efb
commit 2ffca390a9
117 changed files with 5684 additions and 566 deletions

View file

@ -38,6 +38,9 @@ gem 'aasm'
# core - authorization # core - authorization
gem 'pundit' gem 'pundit'
# core - image processing
gem 'rszr', '0.5.2'
# performance - Memcached # performance - Memcached
gem 'dalli' gem 'dalli'
@ -130,8 +133,8 @@ gem 'autodiscover', git: 'https://github.com/zammad-deps/autodiscover'
gem 'rubyntlm', git: 'https://github.com/wimm/rubyntlm' gem 'rubyntlm', git: 'https://github.com/wimm/rubyntlm'
gem 'viewpoint' gem 'viewpoint'
# image processing # integrations - S/MIME
gem 'rszr', '0.5.2' gem 'openssl'
# Gems used only for develop/test and not required # Gems used only for develop/test and not required
# in production environments by default. # in production environments by default.

View file

@ -355,6 +355,7 @@ GEM
omniauth-weibo-oauth2 (0.5.2) omniauth-weibo-oauth2 (0.5.2)
omniauth (~> 1.5) omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0) omniauth-oauth2 (>= 1.4.0)
openssl (2.1.2)
parallel (1.19.1) parallel (1.19.1)
parser (2.7.1.2) parser (2.7.1.2)
ast (~> 2.4.0) ast (~> 2.4.0)
@ -629,6 +630,7 @@ DEPENDENCIES
omniauth-saml omniauth-saml
omniauth-twitter omniauth-twitter
omniauth-weibo-oauth2 omniauth-weibo-oauth2
openssl
pg (= 0.21.0) pg (= 0.21.0)
pre-commit pre-commit
pry-rails pry-rails

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,258 @@
class Index extends App.ControllerIntegrationBase
featureIntegration: 'smime_integration'
featureName: 'S/MIME'
featureConfig: 'smime_config'
description: [
['S/MIME (Secure/Multipurpose Internet Mail Extensions) is a widely accepted method (or more precisely, a protocol) for sending digitally signed and encrypted messages.']
]
events:
'change .js-switch input': 'switch'
render: =>
super
new Form(
el: @$('.js-form')
)
new App.HttpLog(
el: @$('.js-log')
facility: 'S/MIME'
)
class Form extends App.Controller
events:
'click .js-addCertificate': 'addCertificate'
'click .js-addPrivateKey': 'addPrivateKey'
'click .js-updateGroup': 'updateGroup'
constructor: ->
super
@render()
currentConfig: ->
App.Setting.get('smime_config')
setConfig: (value) ->
App.Setting.set('smime_config', value, {notify: true})
render: =>
@config = @currentConfig()
@html App.view('integration/smime')(
config: @config
)
@certList()
@groupList()
certList: =>
new List(el: @$('.js-certList'))
groupList: =>
new Group(
el: @$('.js-groupList')
config: @config
)
addCertificate: =>
new Certificate(
callback: @list
)
addPrivateKey: =>
new PrivateKey(
callback: @list
)
updateGroup: (e) =>
params = App.ControllerForm.params(e)
@setConfig(params)
class Certificate extends App.ControllerModal
buttonClose: true
buttonCancel: true
buttonSubmit: 'Add'
autoFocusOnFirstInput: false
head: 'Add Certificate'
large: true
content: ->
# show start dialog
content = $(App.view('integration/smime_certificate_add')(
head: 'Add Certificate'
))
content
onSubmit: (e) =>
params = new FormData($(e.currentTarget).closest('form').get(0))
params.set('try', true)
if _.isEmpty(params.get('data'))
params.delete('data')
@formDisable(e)
@ajax(
id: 'smime-certificate-add'
type: 'POST'
url: "#{@apiPath}/integration/smime/certificate"
processData: false
contentType: false
cache: false
data: params
success: (data, status, xhr) =>
console.log('success')
@close()
@callback()
error: (data) =>
console.log('error')
@close()
details = data.responseJSON || {}
@notify
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to import!')
timeout: 6000
)
class PrivateKey extends App.ControllerModal
buttonClose: true
buttonCancel: true
buttonSubmit: 'Add'
autoFocusOnFirstInput: false
head: 'Add Private Key'
large: true
content: ->
# show start dialog
content = $(App.view('integration/smime_private_key_add')(
head: 'Add Private Key'
))
content
onSubmit: (e) =>
params = new FormData($(e.currentTarget).closest('form').get(0))
params.set('try', true)
if _.isEmpty(params.get('data'))
params.delete('data')
@formDisable(e)
@ajax(
id: 'smime-private_key-add'
type: 'POST'
url: "#{@apiPath}/integration/smime/private_key"
processData: false
contentType: false
cache: false
data: params
success: (data, status, xhr) =>
@close()
@callback()
error: (data) =>
@close()
details = data.responseJSON || {}
@notify
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to import!')
timeout: 6000
)
class List extends App.Controller
events:
'click .js-remove': 'remove'
constructor: ->
super
@load()
load: =>
@ajax(
id: 'smime-list'
type: 'GET'
url: "#{@apiPath}/integration/smime/certificate"
success: (data, status, xhr) =>
@render(data)
error: (data, status) =>
# do not close window if request is aborted
return if status is 'abort'
details = data.responseJSON || {}
@notify(
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to load list of certificates!')
)
# do something
)
render: (data) =>
@html App.view('integration/smime_list')(
certs: data
)
remove: (e) =>
e.preventDefault()
id = $(e.currentTarget).parents('tr').data('id')
return if !id
@ajax(
id: 'smime-list'
type: 'DELETE'
url: "#{@apiPath}/integration/smime/certificate"
data: JSON.stringify(id: id)
success: (data, status, xhr) =>
@load()
error: (data, status) =>
# do not close window if request is aborted
return if status is 'abort'
details = data.responseJSON || {}
@notify(
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to save!')
)
)
class Group extends App.Controller
constructor: ->
super
@render()
render: (data) =>
groups = App.Group.search(sortBy: 'name', filter: active: true)
@html App.view('integration/smime_group')(
groups: groups
)
for group in groups
for type, selector of { default_sign: 'js-signDefault', default_encryption: 'js-encryptionDefault' }
selected = true
if @config?.group_id && @config.group_id[type]
selected = @config.group_id[type][group.id.toString()]
selection = App.UiElement.boolean.render(
name: "group_id::#{type}::#{group.id}"
multiple: false
null: false
nulloption: false
value: selected
class: 'form-control--small'
)
@$("[data-id=#{group.id}] .#{selector}").html(selection)
class State
@current: ->
App.Setting.get('smime_integration')
App.Config.set(
'Integrationsmime'
{
name: 'S/MIME'
target: '#system/integration/smime'
description: 'S/MIME enables you to send digitally signed and encrypted messages.'
controller: Index
state: State
}
'NavBarIntegrations'
)

View file

@ -428,6 +428,35 @@ class App.UiElement.ticket_perform_action
elementRow.find('.js-setNotification').html(notificationElement).removeClass('hide') elementRow.find('.js-setNotification').html(notificationElement).removeClass('hide')
if App.Config.get('smime_integration') == true
selection = App.UiElement.select.render(
name: "#{name}::sign"
multiple: false
options: {
'no': 'Do not sign email'
'discard': 'Sign email (if not possible, discard notification)'
'always': 'Sign email (if not possible, send notification anyway)'
}
value: meta.sign
translate: true
)
elementRow.find('.js-sign').html(selection)
selection = App.UiElement.select.render(
name: "#{name}::encryption"
multiple: false
options: {
'no': 'Do not encrypt email'
'discard': 'Encrypt email (if not possible, discard notification)'
'always': 'Encrypt email (if not possible, send notification anyway)'
}
value: meta.encryption
translate: true
)
elementRow.find('.js-encryption').html(selection)
@buildArticleArea: (articleType, elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> @buildArticleArea: (articleType, elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
return if elementRow.find(".js-setArticle .js-body-#{articleType}").get(0) return if elementRow.find(".js-setArticle .js-body-#{articleType}").get(0)

View file

@ -1,11 +1,14 @@
class App.TicketCreate extends App.Controller class App.TicketCreate extends App.Controller
@include App.SecurityOptions
elements: elements:
'.tabsSidebar': 'sidebar' '.tabsSidebar': 'sidebar'
events: events:
'click .type-tabs .tab': 'changeFormType' 'click .type-tabs .tab': 'changeFormType'
'submit form': 'submit' 'submit form': 'submit'
'click .js-cancel': 'cancel' 'click .js-cancel': 'cancel'
'click .js-active-toggle': 'toggleButton'
types: { types: {
'phone-in': { 'phone-in': {
@ -121,12 +124,25 @@ class App.TicketCreate extends App.Controller
# force changing signature # force changing signature
@$('[name="group_id"]').trigger('change') @$('[name="group_id"]').trigger('change')
# add observer to change options
@$('[name="cc"], [name="group_id"], [name="customer_id"]').bind('change', =>
@updateSecurityOptions()
)
@updateSecurityOptions()
# show cc # show cc
if type is 'email-out' if type is 'email-out'
@$('[name="cc"]').closest('.form-group').removeClass('hide') @$('[name="cc"]').closest('.form-group').removeClass('hide')
if @securityEnabled()
@securityOptionsShow()
else else
@$('[name="cc"]').closest('.form-group').addClass('hide') @$('[name="cc"]').closest('.form-group').addClass('hide')
if @securityEnabled()
@securityOptionsHide()
# show notice # show notice
@$('.js-note').addClass('hide') @$('.js-note').addClass('hide')
@$(".js-note[data-type='#{type}']").removeClass('hide') @$(".js-note[data-type='#{type}']").removeClass('hide')
@ -165,6 +181,13 @@ class App.TicketCreate extends App.Controller
return false if !diff || _.isEmpty(diff) return false if !diff || _.isEmpty(diff)
return true return true
updateSecurityOptions: =>
params = @params()
if params.customer_id_completion
params.to = params.customer_id_completion
@updateSecurityOptionsRemote(@taskKey, params, params, @paramsSecurity())
autosaveStop: => autosaveStop: =>
@clearDelay('ticket-create-form-update') @clearDelay('ticket-create-form-update')
@el.off('change.local blur.local keyup.local paste.local input.local') @el.off('change.local blur.local keyup.local paste.local input.local')
@ -385,6 +408,9 @@ class App.TicketCreate extends App.Controller
@tokanice() @tokanice()
toggleButton: (event) ->
@$(event.currentTarget).toggleClass('btn--active')
tokanice: -> tokanice: ->
App.Utils.tokanice('.content.active input[name=cc]', 'email') App.Utils.tokanice('.content.active input[name=cc]', 'email')
@ -447,7 +473,7 @@ class App.TicketCreate extends App.Controller
# create article # create article
if sender.name is 'Customer' if sender.name is 'Customer'
params['article'] = { params.article = {
to: (group && group.name) || '' to: (group && group.name) || ''
from: params.customer_id_completion from: params.customer_id_completion
cc: params.cc cc: params.cc
@ -459,7 +485,7 @@ class App.TicketCreate extends App.Controller
content_type: 'text/html' content_type: 'text/html'
} }
else else
params['article'] = { params.article = {
from: (group && group.name) || '' from: (group && group.name) || ''
to: params.customer_id_completion to: params.customer_id_completion
cc: params.cc cc: params.cc
@ -471,6 +497,11 @@ class App.TicketCreate extends App.Controller
content_type: 'text/html' content_type: 'text/html'
} }
# add security params
if @securityOptionsShown()
params.article.preferences ||= {}
params.article.preferences.security = @paramsSecurity()
ticket.load(params) ticket.load(params)
ticketErrorsTop = ticket.validate( ticketErrorsTop = ticket.validate(

View file

@ -709,12 +709,11 @@ class App.TicketZoom extends App.Controller
markFormDiff: (diff = {}) => markFormDiff: (diff = {}) =>
ticketForm = @$('.edit') ticketForm = @$('.edit')
ticketSidebar = @$('.tabsSidebar-tab[data-tab="ticket"]') ticketSidebar = @$('.tabsSidebar-tab[data-tab="ticket"]')
articleForm = @$('.article-add')
resetButton = @$('.js-reset') resetButton = @$('.js-reset')
params = {} params = {}
params.ticket = @forRemoveMeta(@formParam(ticketForm)) params.ticket = @forRemoveMeta(@ticketParams())
params.article = @forRemoveMeta(@formParam(articleForm)) params.article = @forRemoveMeta(@articleNew.params())
# clear all changes # clear all changes
if _.isEmpty(diff.ticket) && _.isEmpty(diff.article) if _.isEmpty(diff.ticket) && _.isEmpty(diff.article)
@ -743,6 +742,9 @@ class App.TicketZoom extends App.Controller
resetButton.removeClass('hide') resetButton.removeClass('hide')
ticketParams: =>
@formParam(@$('.edit'))
submitDisable: (e) => submitDisable: (e) =>
if e if e
@formDisable(e) @formDisable(e)
@ -767,7 +769,7 @@ class App.TicketZoom extends App.Controller
@submitEnable(e) @submitEnable(e)
return return
ticketParams = @formParam(@$('.edit')) ticketParams = @ticketParams()
articleParams = @articleNew.params() articleParams = @articleNew.params()
# validate ticket # validate ticket

View file

@ -253,7 +253,7 @@ class EmailReply extends App.Controller
icon: 'email' icon: 'email'
attributes: attributes attributes: attributes
internal: false, internal: false,
features: ['attachment'] features: ['attachment', 'security']
} }
articleTypes articleTypes

View file

@ -1,4 +1,6 @@
class App.TicketZoomArticleNew extends App.Controller class App.TicketZoomArticleNew extends App.Controller
@include App.SecurityOptions
elements: elements:
'.js-textarea': 'textarea' '.js-textarea': 'textarea'
'.attachmentPlaceholder': 'attachmentPlaceholder' '.attachmentPlaceholder': 'attachmentPlaceholder'
@ -24,6 +26,7 @@ class App.TicketZoomArticleNew extends App.Controller
'click .list-entry-type div': 'changeType' 'click .list-entry-type div': 'changeType'
'focus .js-textarea': 'openTextarea' 'focus .js-textarea': 'openTextarea'
'input .js-textarea': 'updateLetterCount' 'input .js-textarea': 'updateLetterCount'
'click .js-active-toggle': 'toggleButton'
constructor: -> constructor: ->
super super
@ -106,6 +109,12 @@ class App.TicketZoomArticleNew extends App.Controller
@render() @render()
) )
# update security options
@bind('ui::ticket::updateSecurityOptions', (data) =>
return if data.taskKey isnt @taskKey
@updateSecurityOptions()
)
tokanice: (type = 'email') -> tokanice: (type = 'email') ->
App.Utils.tokanice('.content.active .js-to, .js-cc, js-bcc', type) App.Utils.tokanice('.content.active .js-to, .js-cc, js-bcc', type)
@ -294,6 +303,11 @@ class App.TicketZoomArticleNew extends App.Controller
params.body = "#{params.body}\n#{@signature.text()}" params.body = "#{params.body}\n#{@signature.text()}"
break break
# add security params
if @securityOptionsShown()
params.preferences ||= {}
params.preferences.security = @paramsSecurity()
params params
validate: => validate: =>
@ -417,6 +431,15 @@ class App.TicketZoomArticleNew extends App.Controller
@warningTextLength = articleType.warningTextLength @warningTextLength = articleType.warningTextLength
@delay(@updateLetterCount, 600) @delay(@updateLetterCount, 600)
@$('.js-textSizeLimit').removeClass('hide') @$('.js-textSizeLimit').removeClass('hide')
if name is 'security'
if @securityEnabled()
@securityOptionsShow()
# add observer to change options
@$('.js-to, .js-cc').bind('change', =>
@updateSecurityOptions()
)
@updateSecurityOptions()
# convert remote src images to data uri # convert remote src images to data uri
@$('[data-name=body] img').each( (i,image) -> @$('[data-name=body] img').each( (i,image) ->
@ -434,6 +457,9 @@ class App.TicketZoomArticleNew extends App.Controller
@scrollToBottom() if wasScrolledToBottom @scrollToBottom() if wasScrolledToBottom
updateSecurityOptions: =>
@updateSecurityOptionsRemote(@ticket.id, @ui.ticketParams(), @params(), @paramsSecurity())
setArticleTypePost: (type, signaturePosition = 'bottom') => setArticleTypePost: (type, signaturePosition = 'bottom') =>
for localConfig in @actions() for localConfig in @actions()
if localConfig && localConfig.setArticleTypePost if localConfig && localConfig.setArticleTypePost
@ -625,3 +651,6 @@ class App.TicketZoomArticleNew extends App.Controller
if localConfig if localConfig
actions.push localConfig actions.push localConfig
actions actions
toggleButton: (event) ->
@$(event.currentTarget).toggleClass('btn--active')

View file

@ -81,11 +81,13 @@ class ArticleViewItem extends App.ObserverController
'.textBubble-overflowContainer': 'textBubbleOverflowContainer' '.textBubble-overflowContainer': 'textBubbleOverflowContainer'
events: events:
'click .textBubble': 'toggleMetaWithDelay' 'click .article-meta-permanent': 'toggleMetaWithDelay'
'click .textBubble a': 'stopPropagation' 'click .textBubble': 'toggleMetaWithDelay'
'click .js-toggleFold': 'toggleFold' 'click .textBubble a': 'stopPropagation'
'click .richtext-content img': 'imageView' 'click .js-toggleFold': 'toggleFold'
'click .attachments img': 'imageView' 'click .richtext-content img': 'imageView'
'click .attachments img': 'imageView'
'click .js-securityRetryProcess': 'retrySecurityProcess'
constructor: -> constructor: ->
super super
@ -296,6 +298,46 @@ class ArticleViewItem extends App.ObserverController
else else
bubbleOverflowContainer.addClass('hide') bubbleOverflowContainer.addClass('hide')
retrySecurityProcess: (e) ->
e.preventDefault()
e.stopPropagation()
article_id = $(e.target).closest('.ticket-article-item').data('id')
@ajax(
id: 'retrySecurityProcess'
type: 'POST'
url: "#{@apiPath}/ticket_articles/#{article_id}/retry_security_process"
processData: true
success: (data, status, xhr) =>
if data.sign.success
@notify
type: 'success'
msg: App.i18n.translateContent('Verify sign success!')
else if data.sign.comment
comment = App.i18n.translateContent('Verify sign failed!') + ' ' + App.i18n.translateContent(data.sign.comment || '')
@notify
type: 'error'
msg: comment
timeout: 2000
if data.encryption.success
@notify
type: 'success'
msg: App.i18n.translateContent('Decryption success!')
else if data.encryption.comment
comment = App.i18n.translateContent('Decryption failed!') + ' ' + App.i18n.translateContent(data.encryption.comment || '')
@notify
type: 'error'
msg: comment
timeout: 2000
error: (xhr) =>
@notify
type: 'error'
msg: App.i18n.translateContent('Retry security process failed!')
)
stopPropagation: (e) -> stopPropagation: (e) ->
e.stopPropagation() e.stopPropagation()

View file

@ -0,0 +1,10 @@
class TicketZoomFormHandleSecurityOptions
# central method, is getting called on every ticket form change
# but only trigger event for group_id changes
@run: (params, attribute, attributes, classname, form, ui) ->
return if attribute.name isnt 'group_id'
App.Event.trigger('ui::ticket::updateSecurityOptions', { taskKey: ui.taskKey })
App.Config.set('140-ticketFormSecurityOptions', TicketZoomFormHandleSecurityOptions, 'TicketZoomFormHandler')

View file

@ -0,0 +1,89 @@
# Methods for displaying security ui elements and to get security params
App.SecurityOptions =
securityOptionsShow: ->
@$('.js-securityOptions').removeClass('hide')
securityOptionsHide: ->
@$('.js-securityOptions').addClass('hide')
securityOptionsShown: ->
!@$('.js-securityOptions').hasClass('hide')
securityEnabled: ->
App.Config.get('smime_integration')
paramsSecurity: =>
if @$('.js-securityOptions').hasClass('hide')
return {}
security = {}
security.encryption ||= {}
security.sign ||= {}
security.type = 'S/MIME'
if @$('.js-securityEncrypt').hasClass('btn--active')
security.encryption.success = true
if @$('.js-securitySign').hasClass('btn--active')
security.sign.success = true
security
updateSecurityOptionsRemote: (key, ticket, article, securityOptions) ->
callback = =>
@ajax(
id: "smime-check-#{key}"
type: 'POST'
url: "#{@apiPath}/integration/smime"
data: JSON.stringify(ticket: ticket, article: article)
processData: true
success: (data, status, xhr) =>
# get default selected security options
selected =
encryption: true
sign: true
smimeConfig = App.Config.get('smime_config')
for type, selector of { default_sign: 'sign', default_encryption: 'encryption' }
if smimeConfig?.group_id?[type] && ticket.group_id
if smimeConfig.group_id[type][ticket.group_id.toString()] == false
selected[selector] = false
@$('.js-securityEncrypt').attr('title', data.encryption.comment)
# if encryption is possible
if data.encryption.success is true
@$('.js-securityEncrypt').attr('disabled', false)
# overrule current selection with Group configuration
if selected.encryption
@$('.js-securityEncrypt').addClass('btn--active')
else
@$('.js-securityEncrypt').removeClass('btn--active')
# if encryption is not possible
else
@$('.js-securityEncrypt').attr('disabled', true)
@$('.js-securityEncrypt').removeClass('btn--active')
@$('.js-securitySign').attr('title', data.sign.comment)
# if sign is possible
if data.sign.success is true
@$('.js-securitySign').attr('disabled', false)
# overrule current selection with Group configuration
if selected.sign
@$('.js-securitySign').addClass('btn--active')
else
@$('.js-securitySign').removeClass('btn--active')
# if sign is possible
else
@$('.js-securitySign').attr('disabled', true)
@$('.js-securitySign').removeClass('btn--active')
error: (data) ->
details = data.responseJSON || {}
console.log(details)
)
@delay(callback, 200, 'security-check')

View file

@ -27,10 +27,17 @@
<form role="form" class="ticket-create"> <form role="form" class="ticket-create">
<input type="hidden" name="formSenderType"/> <input type="hidden" name="formSenderType"/>
<input type="hidden" name="form_id" value="<%= @form_id %>"/> <input type="hidden" name="form_id" value="<%= @form_id %>"/>
<div class="ticket-form-top"></div> <div class="ticket-form-top"></div>
<div class="form-group js-securityOptions hide">
<div class="formGroup-label">
<label for=""><%- @T('Security') %></label>
</div>
<div class="horizontal">
<div class="btn btn--action js-securityEncrypt js-active-toggle" disabled><%- @Icon('lock-open', 'btn-inactive-icon') %><%- @Icon('lock', 'btn-active-icon') %><%- @T('Encrypt') %></div>
<div class="btn btn--action js-securitySign js-active-toggle" disabled><%- @Icon('not-signed', 'btn-inactive-icon') %><%- @Icon('signed', 'btn-active-icon') %><%- @T('Sign') %></div>
</div>
</div>
<div class="article-form-top"></div> <div class="article-form-top"></div>
<div class="formset-inset"> <div class="formset-inset">
<div class="ticket-form-middle horizontal two-columns"></div> <div class="ticket-form-middle horizontal two-columns"></div>
<div class="ticket-form-bottom"></div> <div class="ticket-form-bottom"></div>

View file

@ -1,5 +1,5 @@
<div class="controls controls--select"> <div class="controls controls--select">
<select id="<%= @attribute.id %>" class="form-control<%= " #{ @attribute.class }" if @attribute.class %>" name="<%= @attribute.name %>" <%= @attribute.multiple %> <%= @attribute.required %> <%= @attribute.autofocus %> <% if @attribute.disabled: %> disabled<% end %>> <select <% if @attribute.id: %>id="<%= @attribute.id %>"<% end %> class="form-control<%= " #{ @attribute.class }" if @attribute.class %>" name="<%= @attribute.name %>" <%= @attribute.multiple %> <%= @attribute.required %> <%= @attribute.autofocus %> <% if @attribute.disabled: %> disabled<% end %>>
<% if @attribute.options: %> <% if @attribute.options: %>
<% for row in @attribute.options: %> <% for row in @attribute.options: %>
<option value="<%= row.value %>" <%= row.selected %> <%= row.disabled %>><%= row.name %></option> <option value="<%= row.value %>" <%= row.selected %> <%= row.disabled %>><%= row.name %></option>

View file

@ -24,5 +24,13 @@
<div class="formGroup-label"> <div class="formGroup-label">
<label><%- @T('Body') %></label> <label><%- @T('Body') %></label>
</div> </div>
<div class="controls js-body js-body-<%- @notificationType %>"><div class="richtext form-control"><div contenteditable="true" data-name="<%= @name %>::body"><%- @meta.body %></div></div></div> <div class="controls js-body js-body-<%- @notificationType %>">
<div class="richtext form-control">
<div contenteditable="true" data-name="<%= @name %>::body"><%- @meta.body %></div>
</div>
</div>
<div class="controls js-sign">
</div>
<div class="controls js-encryption">
</div>
</div> </div>

View file

@ -48,7 +48,7 @@
<thead><tr><th><%- @T('No Entries') %> <thead><tr><th><%- @T('No Entries') %>
</table> </table>
<% else: %> <% else: %>
<table class="settings-list" style="width: 100%;"> <table class="settings-list settings-list--stretch">
<thead> <thead>
<tr> <tr>
<th width="40%"><%- @T('LDAP') %> <th width="40%"><%- @T('LDAP') %>
@ -69,7 +69,7 @@
<thead><tr><th><%- @T('No Entries') %> <thead><tr><th><%- @T('No Entries') %>
</table> </table>
<% else: %> <% else: %>
<table class="settings-list" style="width: 100%;"> <table class="settings-list settings-list--stretch">
<thead> <thead>
<tr> <tr>
<th width="40%"><%- @T('LDAP') %> <th width="40%"><%- @T('LDAP') %>

View file

@ -0,0 +1,14 @@
<form>
<h2><%- @T('Certificates & Private Keys') %></h2>
<div class="settings-entry settings-entry--stretched js-certList"></div>
<div class="btn btn--primary js-addCertificate"><%- @T('Add Certificate') %></div>
<div class="btn js-addPrivateKey"><%- @T('Add Private Key') %></div>
<hr>
<h2><%- @T('Default Behavior') %></h2>
<p>Choose the default behavior of the S/MIME integration on per group basis. If signing or encrypting is not possible, the setting has no effect. Agents call always manually alter the behavior for each article.</p>
<div class="settings-entry settings-entry--stretched js-groupList"></div>
<div class="btn btn--primary js-updateGroup"><%- @T('Update') %></div>
</form>

View file

@ -0,0 +1,26 @@
<div>
<p class="alert alert--danger js-error hide"></p>
<div class="form-group">
<div class="formGroup-label">
<label for="certificate-upload"><%- @T('Upload Certificate') %></label>
</div>
<div class="controls">
<input name="file" type="file" id="certificate-upload">
</div>
</div>
<div class="or-divider">
<span><%- @T('or') %></span>
</div>
<div class="form-group">
<div class="formGroup-label">
<label for="certificate-paste"><%- @T('Paste Certificate') %></label>
</div>
<div class="controls">
<textarea cols="25" rows="20" name="data" style="height: 200px;" id="certificate-paste"></textarea>
</div>
</div>
</div>

View file

@ -0,0 +1,24 @@
<table class="settings-list">
<thead>
<tr>
<th width="55%"><%- @T('Group') %>
<th><%- @T('Sign') %>
<th><%- @T('Encryption') %>
</thead>
<tbody>
<% if _.isEmpty(@groups): %>
<tr>
<td colspan="6">
<%- @T('No Entries') %>
</td>
</tr>
<% else: %>
<% for group in @groups: %>
<tr data-id="<%= group.id %>">
<td><%= group.name %>
<td class="js-signDefault">
<td class="js-encryptionDefault">
<% end %>
<% end %>
</tbody>
</table>

View file

@ -0,0 +1,34 @@
<table class="settings-list settings-list--stretch">
<thead>
<tr>
<th width="55%"><%- @T('Subject') %>
<th width="10%"><%- @T('Hash') %>
<th width="10%"><%- @T('Fingerprint') %>
<th width="10%"><%- @T('Created') %>
<th width="10%"><%- @T('Expires') %>
<th width="5%"><%- @T('Actions') %>
</thead>
<tbody>
<% if _.isEmpty(@certs): %>
<tr>
<td colspan="6">
<%- @T('No Entries') %>
</td>
</tr>
<% else: %>
<% for cert in @certs: %>
<tr data-id="<%= cert.id %>">
<td><%= cert.subject %>
<% if cert.private_key: %><br><i><%- @T('Including private key.') %></i><% end %>
<td><%= cert.doc_hash %>
<td title="<%= cert.fingerprint %>"><%= cert.fingerprint.substr(1, 10) %>...
<td><%- @datetime(cert.not_before_at) %>
<td><%- @datetime(cert.not_after_at) %>
<td>
<div class="btn btn--text js-remove" title="<%- @Ti('Remove') %>">
<%- @Icon('trash') %>
</div>
<% end %>
<% end %>
</tbody>
</table>

View file

@ -0,0 +1,37 @@
<div>
<p class="alert alert--danger js-error hide"></p>
<div class="form-field-group">
<div class="form-group">
<div class="formGroup-label">
<label for="key-upload"><%- @T('Upload Private Key') %></label>
</div>
<div class="controls">
<input name="file" type="file" id="key-upload">
</div>
</div>
<div class="or-divider">
<span><%- @T('or') %></span>
</div>
<div class="form-group">
<div class="formGroup-label">
<label for="key-paste"><%- @T('Paste Private Key') %></label>
</div>
<div class="controls">
<textarea cols="25" rows="20" name="data" style="height: 200px;" id="key-paste"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="formGroup-label">
<label for="key-secret"><%- @T('Enter Private Key secret') %></label>
</div>
<div class="controls">
<input class="form-control" name="secret" type="password" id="key-secret">
</div>
</div>
</div>

View file

@ -4,9 +4,10 @@
<h2>Normal Buttons</h2> <h2>Normal Buttons</h2>
<h3>Default</h3> <h3>Default</h3>
<div class="btn">Default Button</div> <div class="btn">Default Button</div>
<div class="btn btn--active">Active Button</div>
<div class="btn btn--slim">Slim Button</div> <div class="btn btn--slim">Slim Button</div>
<div class="btn is-disabled">Disabled Button (via .is-disabled)</div> <div class="btn is-disabled">.is-disabled Button</div>
<div class="btn" disabled>Disabled Button (via [disabled])</div> <div class="btn" disabled>[disabled] Button</div>
<h3>Primary</h3> <h3>Primary</h3>
<div class="btn btn--primary">Primary Button</div> <div class="btn btn--primary">Primary Button</div>
@ -24,6 +25,7 @@
<div class="horizontal"> <div class="horizontal">
<div class="btn btn--split--first">Split First Button</div> <div class="btn btn--split--first">Split First Button</div>
<div class="btn btn--split">Split Button</div> <div class="btn btn--split">Split Button</div>
<div class="btn btn--split btn--active">Active Split Button</div>
<div class="btn btn--split--last">Split Last Button</div> <div class="btn btn--split--last">Split Last Button</div>
</div> </div>

View file

@ -56,6 +56,15 @@
</div> </div>
<div class="controls"><input type="text" name="subject" value="<%= @article.subject %>" class="form-control js-mail-inputs2 js-subject"></div> <div class="controls"><input type="text" name="subject" value="<%= @article.subject %>" class="form-control js-mail-inputs2 js-subject"></div>
</div> </div>
<div class="form-group js-securityOptions">
<div class="formGroup-label">
<label for=""><%- @T('Security') %></label>
</div>
<div class="horizontal">
<div class="btn btn--action js-securityEncrypt js-active-toggle" disabled><%- @Icon('lock-open', 'btn-inactive-icon') %><%- @Icon('lock', 'btn-active-icon') %><%- @T('Encrypt') %></div>
<div class="btn btn--action js-securitySign js-active-toggle" disabled><%- @Icon('not-signed', 'btn-inactive-icon') %><%- @Icon('signed', 'btn-active-icon') %><%- @T('Sign') %></div>
</div>
</div>
<div class="textBubble js-writeArea"> <div class="textBubble js-writeArea">
<div class="bubble-arrow"></div> <div class="bubble-arrow"></div>

View file

@ -31,9 +31,51 @@
<div class="article-meta-value flex contain-text"><%= @article.subject %></div> <div class="article-meta-value flex contain-text"><%= @article.subject %></div>
</div> </div>
<% end %> <% end %>
<% if @article.preferences.security?.encryption?.success || @article.preferences.security?.sign?.success: %>
<div class="horizontal article-meta-row">
<div class="article-meta-key u-textTruncate"><%- @T('Security') %></div>
<div class="article-meta-value flex contain-text">
<% if @article.preferences.security?.encryption?.success: %>
<span title="<%- @Ti(@article.preferences.security?.encryption?.comment) %>"><%- @Icon('lock', 'article-meta-icon') %> <%- @T('Encrypted') %></span>
<% end %>
<% if @article.preferences.security?.encryption?.success && @article.preferences.security?.sign?.success: %>
,
<% end %>
<% if @article.preferences.security?.sign?.success is not null: %>
<span title="<%- @Ti(@article.preferences.security?.sign?.comment) %>"><%- @Icon((if @article.preferences.security?.sign?.success is true then 'signed' else 'not-signed'), 'article-meta-icon') %> <%- @T(if @article.preferences.security?.sign?.success is true then 'Signed' else 'Unsigned') %></span>
<% end %>
</div>
</div>
<% end %>
</div> </div>
</div> </div>
</div> </div>
<div class="article-meta-permanent">
<% if (@article.preferences.security?.sign?.success is false && @article.preferences.security?.sign?.comment) || (@article.preferences.security?.encryption?.success is false && @article.preferences.security?.encryption?.comment): %>
<div class="alert alert--warning">
<%- @Icon('not-signed') %> <%- @T('Security Error') %>
<% if @article.preferences.security?.sign?.success is false && @article.preferences.security?.sign?.comment: %>
<br>
<%- @T('Sign') %>: <%- @T(@article.preferences.security?.sign?.comment) %>
<% end %>
<% if @article.preferences.security?.encryption?.success is false && @article.preferences.security?.encryption?.comment: %>
<br>
<%- @T('Encryption') %>: <%- @T(@article.preferences.security?.encryption?.comment) %>
<% end %>
<div class="flex-spacer"></div>
<div class="btn btn--action btn--small js-securityRetryProcess"><%- @T('Retry security process') %></div>
</div>
<% else if @article.preferences.security?.encryption?.success is true || @article.preferences.security?.sign?.success is true: %>
<div class="alert alert--blank horizontal">
<% if @article.preferences.security?.encryption?.success is true: %>
<span title="<%- @T('Encrypted') %>"><%- @Icon('lock') %></span>
<% end %>
<% if @article.preferences.security?.sign?.success is true: %>
<span title="<%- @T('Signed') %>"><%- @Icon('signed') %></span>
<% end %>
</div>
<% end %>
</div>
<div class="article-content"> <div class="article-content">
<% if @article.sender.name isnt 'Agent': %> <% if @article.sender.name isnt 'Agent': %>
<% position = 'left' %> <% position = 'left' %>

View file

@ -81,6 +81,7 @@
.icon-mood-superbad { width: 60px; height: 59px; } .icon-mood-superbad { width: 60px; height: 59px; }
.icon-mood-supergood { width: 60px; height: 59px; } .icon-mood-supergood { width: 60px; height: 59px; }
.icon-mute { width: 16px; height: 16px; } .icon-mute { width: 16px; height: 16px; }
.icon-not-signed { width: 14px; height: 14px; }
.icon-note { width: 16px; height: 16px; } .icon-note { width: 16px; height: 16px; }
.icon-oauth2-button { width: 29px; height: 24px; } .icon-oauth2-button { width: 29px; height: 24px; }
.icon-office365-button { width: 29px; height: 24px; } .icon-office365-button { width: 29px; height: 24px; }
@ -107,6 +108,7 @@
.icon-reply { width: 16px; height: 17px; } .icon-reply { width: 16px; height: 17px; }
.icon-report { width: 20px; height: 20px; } .icon-report { width: 20px; height: 20px; }
.icon-searchdetail { width: 18px; height: 14px; } .icon-searchdetail { width: 18px; height: 14px; }
.icon-signed { width: 14px; height: 14px; }
.icon-signout { width: 15px; height: 19px; } .icon-signout { width: 15px; height: 19px; }
.icon-small-dot { width: 16px; height: 16px; } .icon-small-dot { width: 16px; height: 16px; }
.icon-sms { width: 17px; height: 17px; } .icon-sms { width: 17px; height: 17px; }

View file

@ -155,7 +155,6 @@ a {
&.is-disabled, &.is-disabled,
&[disabled] { &[disabled] {
pointer-events: none;
cursor: not-allowed !important; cursor: not-allowed !important;
opacity: .33; opacity: .33;
} }
@ -443,7 +442,6 @@ pre code.hljs {
&.is-disabled, &.is-disabled,
&[disabled], &[disabled],
&:disabled { &:disabled {
pointer-events: none;
cursor: not-allowed; cursor: not-allowed;
opacity: .33; opacity: .33;
} }
@ -492,20 +490,32 @@ pre code.hljs {
} }
&.btn--small { &.btn--small {
height: 27px; height: 26px;
font-size: 11px; font-size: 11px;
padding-left: 8px; padding-left: 8px;
padding-right: 8px; padding-right: 8px;
} }
} }
&-active-icon {
display: none;
}
&--active { &--active {
background: hsla(0,0%,0%,.5); background: hsl(204,7%,28%);
color: white; color: white;
&:active { &:active {
background: hsla(0,0%,0%,.55); background: hsla(0,0%,0%,.55);
} }
.btn-inactive-icon {
display: none;
}
.btn-active-icon {
display: inline;
}
} }
// used in .recipientList-controls // used in .recipientList-controls
@ -531,9 +541,11 @@ pre code.hljs {
&--primary { &--primary {
color: white; color: white;
background: hsl(203,65%,55%); background: hsl(203,65%,55%);
&:active { &:active {
background: hsl(203,65%,45%); background: hsl(203,65%,45%);
} }
.icon { .icon {
fill: white; fill: white;
opacity: 1; opacity: 1;
@ -1543,7 +1555,7 @@ label,
.checkbox.form-group label, .checkbox.form-group label,
.label { .label {
text-transform: uppercase; text-transform: uppercase;
color: hsl(198,19%,72%); color: hsl(198,15%,69%);
display: block; display: block;
font-size: 13px; font-size: 13px;
font-weight: normal; font-weight: normal;
@ -1658,6 +1670,18 @@ https://stackoverflow.com/questions/17408815/fieldset-resizes-wrong-appears-to-h
fieldset { display: table-cell; } fieldset { display: table-cell; }
} }
.form-field-group {
padding: 20px;
background: hsl(0,0%,97%);
--background: hsl(0,0%,97%);
border-radius: 4px;
margin-bottom: 16px;
> .form-group:last-child {
margin-bottom: 0;
}
}
fieldset > .form-group { fieldset > .form-group {
padding: 0 4px; padding: 0 4px;
} }
@ -5660,12 +5684,63 @@ footer {
vertical-align: top; vertical-align: top;
margin: 2px 3px 0 0; margin: 2px 3px 0 0;
@include rtl(margin, 2px 0 0 3px); @include rtl(margin, 2px 0 0 3px);
&.icon-lock {
margin: 0;
}
} }
.article-meta .text-muted { .article-meta .text-muted {
color: #96969b; color: #96969b;
} }
.article-meta-permanent {
margin: 0 55px;
+ .article-content .textBubble {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-top-width: 0;
}
.alert {
margin-bottom: 0;
padding-left: 20px;
padding-right: 20px;
border-radius: 0;
box-shadow: 0 0 0 1px inset hsla(0,0%,0%,.04);
&:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
&--blank {
background: hsl(212,14%,99%);
color: hsl(198,16%,70%);
.customer.ticket-article-item & {
background: hsl(201,43%,96%);
border-color: hsl(203,38%,92%);
}
}
.icon {
fill: currentColor;
margin: 2px 6px 0 0;
vertical-align: top;
width: 14px;
height: 14px;
}
.icon-lock {
margin-top: 1px;
width: 16px;
height: 16px;
}
}
}
.internal-border { .internal-border {
padding: 5px; padding: 5px;
border-radius: 8px; border-radius: 8px;
@ -5775,7 +5850,7 @@ footer {
.bubble-arrow { .bubble-arrow {
position: absolute; position: absolute;
width: 7px; width: 6px;
height: 9px; height: 9px;
left: -6px; left: -6px;
top: 15px; top: 15px;
@ -5786,7 +5861,7 @@ footer {
content: ""; content: "";
position: absolute; position: absolute;
top: -1px; top: -1px;
left: 2px; left: 1px;
width: 11px; width: 11px;
height: 11px; height: 11px;
background: white; background: white;
@ -6724,6 +6799,15 @@ footer {
&--square { &--square {
border-radius: 0; border-radius: 0;
} }
.btn {
margin-top: -4px;
margin-bottom: -5px;
&:last-child {
margin-right: -5px;
}
}
} }
.tags, .tags,
@ -7412,7 +7496,6 @@ footer {
.dropdown-icon { .dropdown-icon {
width: 16px; width: 16px;
height: 16px; height: 16px;
opacity: 0.39;
} }
.dropdown-menu.dropdown-menu--light { .dropdown-menu.dropdown-menu--light {
@ -8020,9 +8103,37 @@ footer {
} }
} }
.or-divider {
position: relative;
margin: 16px 0;
text-align: center;
&:before {
content: "";
position: absolute;
left: 0;
width: 100%;
top: 50%;
margin-top: -1px;
height: 1px;
background: hsla(0,0%,0%,.1);
}
span {
position: relative;
background: white;
background: var(--background, white);
padding: 0 10px;
}
}
.settings-entry { .settings-entry {
margin-bottom: 42px; margin-bottom: 42px;
max-width: 700px; max-width: 700px;
&--stretched {
max-width: none;
}
} }
.setting-controls { .setting-controls {

View file

@ -0,0 +1,154 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class Integration::SMIMEController < ApplicationController
prepend_before_action { authentication_check && authorize! }
def certificate_list
render json: SMIMECertificate.all
end
def certificate_delete
SMIMECertificate.find(params[:id]).destroy!
render json: {
result: 'ok',
}
end
def certificate_add
string = params[:data]
if string.blank? && params[:file].present?
string = params[:file].read.force_encoding('utf-8')
end
item = SMIMECertificate.create!(public_key: string)
render json: {
result: 'ok',
response: item,
}
rescue => e
unprocessable_entity(e)
end
def private_key_delete
SMIMECertificate.find(params[:id]).update!(
private_key: nil,
private_key_secret: nil,
)
render json: {
result: 'ok',
}
end
def private_key_add
string = params[:data]
if string.blank? && params[:file].present?
string = params[:file].read.force_encoding('utf-8')
end
raise "Parameter 'data' or 'file' required." if string.blank?
private_key = OpenSSL::PKey.read(string, params[:secret])
modulus = private_key.public_key.n.to_s(16)
certificate = SMIMECertificate.find_by(modulus: modulus)
raise Exceptions::UnprocessableEntity, 'Unable for find certificate for this private key.' if !certificate
certificate.update!(private_key: string, private_key_secret: params[:secret])
render json: {
result: 'ok',
}
rescue => e
unprocessable_entity(e)
end
def search
result = {
type: 'S/MIME',
}
result[:encryption] = article_encryption(params[:article])
result[:sign] = article_sign(params[:ticket])
render json: result
end
def article_encryption(article)
result = {
success: false,
comment: 'no recipient found',
}
return result if article.blank?
return result if article[:to].blank? && article[:cc].blank?
recipient = [ article[:to], article[:cc] ].compact.join(',').to_s
recipients = []
begin
list = Mail::AddressList.new(recipient)
list.addresses.each do |address|
recipients.push address.address
end
rescue # rubocop:disable Lint/SuppressedException
end
return result if recipients.blank?
begin
certs = SMIMECertificate.for_recipipent_email_addresses!(recipients)
if certs
if certs.any?(&:expired?)
result[:success] = false
result[:comment] = "certificates found for #{recipients.join(',')} but expired"
else
result[:success] = true
result[:comment] = "certificates found for #{recipients.join(',')}"
end
end
rescue => e
result[:comment] = e.message
end
result
end
def article_sign(ticket)
result = {
success: false,
comment: 'certificate not found',
}
return result if ticket.blank? || !ticket[:group_id]
group = Group.find_by(id: ticket[:group_id])
return result if !group
email_address = group.email_address
begin
list = Mail::AddressList.new(email_address.email)
from = list.addresses.first.to_s
cert = SMIMECertificate.for_sender_email_address(from)
if cert
if cert.expired?
result[:success] = false
result[:comment] = "certificate for #{email_address.email} found but expired"
else
result[:success] = true
result[:comment] = "certificate for #{email_address.email} found"
end
else
result[:success] = false
result[:comment] = "no certificate for #{email_address.email} found"
end
rescue => e
result[:comment] = e.message
end
result
end
end

View file

@ -263,6 +263,15 @@ class TicketArticlesController < ApplicationController
render json: result, status: :ok render json: result, status: :ok
end end
def retry_security_process
article = Ticket::Article.find(params[:id])
authorize!(article, :update?)
result = SecureMailing.retry(article)
render json: result
end
private private
def sanitized_disposition def sanitized_disposition

View file

@ -62,7 +62,8 @@ class TicketArticleCommunicateEmailJob < ApplicationJob
subject: subject, subject: subject,
content_type: record.content_type, content_type: record.content_type,
body: record.body, body: record.body,
attachments: record.attachments attachments: record.attachments,
security: record.preferences[:security],
}, },
notification notification
) )

View file

@ -3,6 +3,8 @@ module Channel::EmailBuild
=begin =begin
generate email
mail = Channel::EmailBuild.build( mail = Channel::EmailBuild.build(
from: 'sender@example.com', from: 'sender@example.com',
to: 'recipient@example.com', to: 'recipient@example.com',
@ -10,35 +12,37 @@ module Channel::EmailBuild
content_type: 'text/plain', content_type: 'text/plain',
) )
generate email with S/MIME
mail = Channel::EmailBuild.build(
from: 'sender@example.com',
to: 'recipient@example.com',
body: 'somebody with some text',
content_type: 'text/plain',
security: {
type: 'S/MIME',
encryption: {
success: true,
},
sign: {
success: true,
},
}
)
=end =end
def self.build(attr, notification = false) def self.build(attr, notification = false)
mail = Mail.new mail = Mail.new
# set organization
organization = Setting.get('organization')
if organization
mail['Organization'] = organization.to_s
end
# notification
if notification
attr['X-Loop'] = 'yes'
attr['Precedence'] = 'bulk'
attr['Auto-Submitted'] = 'auto-generated'
attr['X-Auto-Response-Suppress'] = 'All'
end
attr['X-Powered-By'] = 'Zammad - Helpdesk/Support (https://zammad.org/)'
attr['X-Mailer'] = 'Zammad Mail Service'
# set headers # set headers
attr.each do |key, value| attr.each do |key, value|
next if key.to_s == 'attachments' next if key.to_s == 'attachments'
next if key.to_s == 'body' next if key.to_s == 'body'
next if key.to_s == 'content_type' next if key.to_s == 'content_type'
next if key.to_s == 'security'
mail[key.to_s] = if value && value.class != Array mail[key.to_s] = if value.present? && value.class != Array
value.to_s value.to_s
else else
value value
@ -70,6 +74,7 @@ module Channel::EmailBuild
if !html_alternative && attr[:attachments].blank? if !html_alternative && attr[:attachments].blank?
mail.content_type 'text/plain; charset=UTF-8' mail.content_type 'text/plain; charset=UTF-8'
mail.body attr[:body] mail.body attr[:body]
SecureMailing.outgoing(mail, attr[:security])
return mail return mail
end end
@ -119,6 +124,25 @@ module Channel::EmailBuild
} }
end end
end end
SecureMailing.outgoing(mail, attr[:security])
# set organization
organization = Setting.get('organization')
if organization.present?
mail['Organization'] = organization.to_s
end
if notification
mail['X-Loop'] = 'yes'
mail['Precedence'] = 'bulk'
mail['Auto-Submitted'] = 'auto-generated'
mail['X-Auto-Response-Suppress'] = 'All'
end
mail['X-Powered-By'] = 'Zammad - Helpdesk/Support (https://zammad.org/)'
mail['X-Mailer'] = 'Zammad Mail Service'
mail mail
end end

View file

@ -87,6 +87,7 @@ class Channel::EmailParser
headers, headers,
body, body,
self.class.sender_attributes(headers), self.class.sender_attributes(headers),
raw: msg,
] ]
message_attributes.reduce({}.with_indifferent_access, &:merge) message_attributes.reduce({}.with_indifferent_access, &:merge)
end end

View file

@ -0,0 +1,8 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
module Channel::Filter::SecureMailing
def self.run(_channel, mail)
::SecureMailing.incoming(mail)
end
end

View file

@ -0,0 +1,99 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class SMIMECertificate < ApplicationModel
validates :fingerprint, uniqueness: true
def self.parse(raw)
OpenSSL::X509::Certificate.new(raw.gsub!(/(?:TRUSTED\s)?(CERTIFICATE---)/, '\1'))
end
# Search for the certificate of the given sender email address
#
# @example
# certificate = SMIMECertificates.for_sender_email_address('some1@example.com')
# # => #<SMIMECertificate:0x00007fdd4e27eec0...
#
# @return [SMIMECertificate, nil] The found certificate record or nil
def self.for_sender_email_address(address)
downcased_address = address.downcase
where.not(private_key: nil).find_each.detect do |certificate|
certificate.email_addresses.include?(downcased_address)
end
end
# Search for certificates of the given recipients email addresses
#
# @example
# certificates = SMIMECertificates.for_recipipent_email_addresses!(['some1@example.com', 'some2@example.com'])
# # => [#<SMIMECertificate:0x00007fdd4e27eec0...
#
# @raise [ActiveRecord::RecordNotFound] if there are recipients for which no certificate could be found
#
# @return [Array<SMIMECertificate>] The found certificate records
def self.for_recipipent_email_addresses!(addresses)
certificates = []
remaining_addresses = addresses.map(&:downcase)
find_each do |certificate|
# intersection of both lists
cerfiticate_for = certificate.email_addresses & remaining_addresses
next if cerfiticate_for.blank?
certificates.push(certificate)
# subtract found recipient(s)
remaining_addresses -= cerfiticate_for
# end loop if no addresses are remaining
break if remaining_addresses.blank?
end
return certificates if remaining_addresses.blank?
raise ActiveRecord::RecordNotFound, "Can't find S/MIME encryption certificates for: #{remaining_addresses.join(', ')}"
end
def public_key=(string)
cert = self.class.parse(string)
self.subject = cert.subject
self.doc_hash = cert.subject.hash.to_s(16)
self.fingerprint = OpenSSL::Digest.new('SHA1', cert.to_der).to_s
self.modulus = cert.public_key.n.to_s(16)
self.not_before_at = cert.not_before
self.not_after_at = cert.not_after
self.raw = cert.to_s
end
def parsed
@parsed ||= self.class.parse(raw)
end
def email_addresses
@email_addresses ||= begin
subject_alt_name = parsed.extensions.detect { |extension| extension.oid == 'subjectAltName' }
if subject_alt_name.blank?
warning = <<~TEXT.squish
SMIMECertificate with ID #{id} has no subjectAltName
extension and therefore no email addresses assigned.
This makes it useless in terms of S/MIME. Please check.
TEXT
Rails.logger.warn warning
return []
end
# ["IP Address:192.168.7.23", "IP Address:192.168.7.42", "email:jd@example.com", "email:John.Doe@example.com", "dirName:dir_sect"]
entries = subject_alt_name.value.split(/,\s?/)
# ["email:jd@example.com", "email:John.Doe@example.com"]
email_address_entries = entries.select { |entry| entry.start_with?('email') }
# ["jd@example.com", "John.Doe@example.com"]
email_address_entries.map! { |entry| entry.split(':')[1] }
# ["jd@example.com", "john.doe@example.com"]
email_address_entries.map!(&:downcase)
end
end
def expired?
!Time.zone.now.between?(not_before_at, not_after_at)
end
end

View file

@ -1498,6 +1498,57 @@ result
return return
end end
security = nil
if Setting.get('smime_integration')
sign = value['sign'].present? && value['sign'] != 'no'
encryption = value['encryption'].present? && value['encryption'] != 'no'
security = {
type: 'S/MIME',
sign: {
success: false,
},
encryption: {
success: false,
},
}
if sign
sign_found = false
begin
list = Mail::AddressList.new(email_address.email)
from = list.addresses.first.to_s
cert = SMIMECertificate.for_sender_email_address(from)
if cert && !cert.expired?
sign_found = true
security[:sign][:success] = true
security[:sign][:comment] = "certificate for #{email_address.email} found"
end
rescue # rubocop:disable Lint/SuppressedException
end
if value['sign'] == 'discard' && !sign_found
logger.info "Unable to send trigger based notification to #{recipient_string} because of missing group #{group.name} email #{email_address.email} certificate for signing (discarding notification)."
return
end
end
if encryption
certs_found = false
begin
SMIMECertificate.for_recipipent_email_addresses!(recipients_checked)
certs_found = true
security[:encryption][:success] = true
security[:encryption][:comment] = "certificates found for #{recipient_string}"
rescue # rubocop:disable Lint/SuppressedException
end
if value['encryption'] == 'discard' && !certs_found
logger.info "Unable to send trigger based notification to #{recipient_string} because public certificate is not available for encryption (discarding notification)."
return
end
end
end
objects = build_notification_template_objects(article) objects = build_notification_template_objects(article)
# get subject # get subject
@ -1516,6 +1567,12 @@ result
(body, attachments_inline) = HtmlSanitizer.replace_inline_images(body, id) (body, attachments_inline) = HtmlSanitizer.replace_inline_images(body, id)
preferences = {}
preferences[:perform_origin] = perform_origin
if security.present?
preferences[:security] = security
end
message = Ticket::Article.create( message = Ticket::Article.create(
ticket_id: id, ticket_id: id,
to: recipient_string, to: recipient_string,
@ -1525,9 +1582,7 @@ result
internal: value['internal'] || false, # default to public if value was not set internal: value['internal'] || false, # default to public if value was not set
sender: Ticket::Article::Sender.find_by(name: 'System'), sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'email'), type: Ticket::Article::Type.find_by(name: 'email'),
preferences: { preferences: preferences,
perform_origin: perform_origin,
},
updated_by_id: 1, updated_by_id: 1,
created_by_id: 1, created_by_id: 1,
) )

View file

@ -337,4 +337,5 @@ returns
o_id: id, o_id: id,
) )
end end
end end

View file

@ -0,0 +1,4 @@
class Controllers::Integration::SMIMEControllerPolicy < Controllers::ApplicationControllerPolicy
permit! :search, to: 'ticket.agent'
default_permit!('admin.integration.smime')
end

View file

@ -20,4 +20,5 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
# Rails thinks the singularized version of knowledge_bases is knowledge_basis?! # Rails thinks the singularized version of knowledge_bases is knowledge_basis?!
# see: KnowledgeBase.table_name.singularize # see: KnowledgeBase.table_name.singularize
inflect.singular(/(knowledge_base)s$/i, '\1') inflect.singular(/(knowledge_base)s$/i, '\1')
inflect.acronym 'SMIME'
end end

View file

@ -0,0 +1,10 @@
Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
match api_path + '/integration/smime', to: 'integration/smime#search', via: :post
match api_path + '/integration/smime/certificate', to: 'integration/smime#certificate_add', via: :post
match api_path + '/integration/smime/certificate', to: 'integration/smime#certificate_delete', via: :delete
match api_path + '/integration/smime/certificate', to: 'integration/smime#certificate_list', via: :get
match api_path + '/integration/smime/private_key', to: 'integration/smime#private_key_add', via: :post
match api_path + '/integration/smime/private_key', to: 'integration/smime#private_key_delete', via: :delete
end

View file

@ -45,5 +45,5 @@ Zammad::Application.routes.draw do
match api_path + '/ticket_attachment/:ticket_id/:article_id/:id', to: 'ticket_articles#attachment', via: :get match api_path + '/ticket_attachment/:ticket_id/:article_id/:id', to: 'ticket_articles#attachment', via: :get
match api_path + '/ticket_attachment_upload_clone_by_article/:article_id', to: 'ticket_articles#ticket_attachment_upload_clone_by_article', via: :post match api_path + '/ticket_attachment_upload_clone_by_article/:article_id', to: 'ticket_articles#ticket_attachment_upload_clone_by_article', via: :post
match api_path + '/ticket_article_plain/:id', to: 'ticket_articles#article_plain', via: :get match api_path + '/ticket_article_plain/:id', to: 'ticket_articles#article_plain', via: :get
match api_path + '/ticket_articles/:id/retry_security_process', to: 'ticket_articles#retry_security_process', via: :post
end end

View file

@ -131,7 +131,7 @@ $imageTypes = '{*.svg}';
# Set to true if you prefer sorting images by name # Set to true if you prefer sorting images by name
# If set to false, images will be sorted by date # If set to false, images will be sorted by date
$sortByImageName = false; $sortByImageName = true;
# Set to false if you want the oldest images to appear first # Set to false if you want the oldest images to appear first
# This is only used if images are sorted by date (see above) # This is only used if images are sorted by date (see above)

Binary file not shown.

View file

@ -724,5 +724,21 @@ class CreateBase < ActiveRecord::Migration[4.2]
end end
add_index :active_job_locks, :lock_key, unique: true add_index :active_job_locks, :lock_key, unique: true
add_index :active_job_locks, :active_job_id, unique: true add_index :active_job_locks, :active_job_id, unique: true
create_table :smime_certificates do |t|
t.string :subject, limit: 500, null: false
t.string :doc_hash, limit: 250, null: false
t.string :fingerprint, limit: 250, null: false
t.string :modulus, limit: 1024, null: false
t.datetime :not_before_at, null: true
t.datetime :not_after_at, null: true
t.binary :raw, limit: 10.megabytes, null: false
t.binary :private_key, limit: 10.megabytes, null: true
t.string :private_key_secret, limit: 500, null: true
t.timestamps limit: 3, null: false
end
add_index :smime_certificates, [:fingerprint], unique: true
add_index :smime_certificates, [:modulus]
add_index :smime_certificates, [:subject]
end end
end end

View file

@ -0,0 +1,74 @@
class SMIMESupport < ActiveRecord::Migration[5.2]
def up
# return if it's a new setup
return if !Setting.find_by(name: 'system_init_done')
Setting.create_if_not_exists(
title: 'S/MIME integration',
name: 'smime_integration',
area: 'Integration::Switch',
description: 'Defines if S/MIME encryption is enabled or not.',
options: {
form: [
{
display: '',
null: true,
name: 'smime_integration',
tag: 'boolean',
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: false,
preferences: {
prio: 1,
authentication: true,
permission: ['admin.integration'],
},
frontend: true
)
Setting.create_if_not_exists(
title: 'S/MIME config',
name: 'smime_config',
area: 'Integration::SMIME',
description: 'Defines the S/MIME config.',
options: {},
state: {},
preferences: {
prio: 2,
permission: ['admin.integration'],
},
frontend: true,
)
Setting.create_if_not_exists(
title: 'Defines postmaster filter.',
name: '0016_postmaster_filter_smime',
area: 'Postmaster::PreFilter',
description: 'Defines postmaster filter to handle secure mailing.',
options: {},
state: 'Channel::Filter::SecureMailing',
frontend: false
)
create_table :smime_certificates do |t|
t.string :subject, limit: 500, null: false
t.string :doc_hash, limit: 250, null: false
t.string :fingerprint, limit: 250, null: false
t.string :modulus, limit: 1024, null: false
t.datetime :not_before_at, null: true
t.datetime :not_after_at, null: true
t.binary :raw, limit: 10.megabytes, null: false
t.binary :private_key, limit: 10.megabytes, null: true
t.string :private_key_secret, limit: 500, null: true
t.timestamps limit: 3, null: false
end
add_index :smime_certificates, [:fingerprint], unique: true
add_index :smime_certificates, [:modulus]
add_index :smime_certificates, [:subject]
end
end

View file

@ -3349,6 +3349,15 @@ Setting.create_if_not_exists(
state: 'Channel::Filter::IdentifySender', state: 'Channel::Filter::IdentifySender',
frontend: false frontend: false
) )
Setting.create_if_not_exists(
title: 'Defines postmaster filter.',
name: '0016_postmaster_filter_smime',
area: 'Postmaster::PreFilter',
description: 'Defines postmaster filter to handle secure mailing.',
options: {},
state: 'Channel::Filter::SecureMailing',
frontend: false
)
Setting.create_if_not_exists( Setting.create_if_not_exists(
title: 'Defines postmaster filter.', title: 'Defines postmaster filter.',
name: '0020_postmaster_filter_auto_response_check', name: '0020_postmaster_filter_auto_response_check',
@ -4549,3 +4558,45 @@ Setting.create_if_not_exists(
}, },
frontend: true frontend: true
) )
Setting.create_if_not_exists(
title: 'S/MIME integration',
name: 'smime_integration',
area: 'Integration::Switch',
description: 'Defines if S/MIME encryption is enabled or not.',
options: {
form: [
{
display: '',
null: true,
name: 'smime_integration',
tag: 'boolean',
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: false,
preferences: {
prio: 1,
authentication: true,
permission: ['admin.integration'],
},
frontend: true
)
Setting.create_if_not_exists(
title: 'S/MIME config',
name: 'smime_config',
area: 'Integration::SMIME',
description: 'Defines the S/MIME config.',
options: {},
state: {},
preferences: {
prio: 2,
permission: ['admin.integration'],
},
frontend: true,
)

25
lib/secure_mailing.rb Normal file
View file

@ -0,0 +1,25 @@
class SecureMailing
include ::Mixin::HasBackends
def self.incoming(mail)
active_backends.each do |backend|
"#{backend}::Incoming".constantize.process(mail)
end
end
def self.retry(article)
active_backends.each do |backend|
"#{backend}::Retry".constantize.process(article)
end
end
def self.outgoing(mail, security)
active_backends.each do |backend|
"#{backend}::Outgoing".constantize.process(mail, security)
end
end
def self.active_backends
backends.select(&:active?)
end
end

View file

@ -0,0 +1,9 @@
class SecureMailing::Backend
include Mixin::IsBackend
def self.inherited(subclass)
subclass.is_backend_of(::SecureMailing)
end
end
Mixin::RequiredSubPaths.eager_load_recursive(__dir__)

View file

@ -0,0 +1,6 @@
class SecureMailing::Backend::Handler
def self.process(*args)
new(*args).process
end
end

View file

@ -0,0 +1,6 @@
class SecureMailing::SMIME < SecureMailing::Backend
def self.active?
Setting.get('smime_integration')
end
end

View file

@ -0,0 +1,180 @@
class SecureMailing::SMIME::Incoming < SecureMailing::Backend::Handler
EXPRESSION_MIME = %r{application/(x-pkcs7|pkcs7)-mime}i.freeze
EXPRESSION_SIGNATURE = %r{application/(x-pkcs7|pkcs7)-signature}i.freeze
OPENSSL_PKCS7_VERIFY_FLAGS = OpenSSL::PKCS7::NOVERIFY | OpenSSL::PKCS7::NOINTERN
def initialize(mail)
@mail = mail
@content_type = @mail[:mail_instance].content_type
end
def process
return if !process?
initialize_article_preferences
decrypt
verify_signature
log
end
def initialize_article_preferences
article_preferences[:security] = {
type: 'S/MIME',
sign: {
success: false,
comment: nil,
},
encryption: {
success: false,
comment: nil,
}
}
end
def article_preferences
@article_preferences ||= begin
key = 'x-zammad-article-preferences'.to_sym
@mail[ key ] ||= {}
@mail[ key ]
end
end
def process?
signed? || smime?
end
def signed?(content_type = @content_type)
EXPRESSION_SIGNATURE.match?(content_type)
end
def smime?(content_type = @content_type)
EXPRESSION_MIME.match?(content_type)
end
def decrypt
return if !smime?
success = false
comment = 'Unable to find private key to decrypt'
::SMIMECertificate.where.not(private_key: [nil, '']).find_each do |cert|
key = OpenSSL::PKey::RSA.new(cert.private_key, cert.private_key_secret)
begin
decrypted_data = p7enc.decrypt(key, cert.parsed)
rescue
next
end
@mail[:mail_instance].header['Content-Type'] = nil
@mail[:mail_instance].header['Content-Disposition'] = nil
@mail[:mail_instance].header['Content-Transfer-Encoding'] = nil
@mail[:mail_instance].header['Content-Description'] = nil
new_raw_mail = "#{@mail[:mail_instance].header}#{decrypted_data}"
mail_new = Channel::EmailParser.new.parse(new_raw_mail)
mail_new.each do |local_key, local_value|
@mail[local_key] = local_value
end
success = true
comment = cert.subject
if cert.expired?
comment += " (Certificate #{cert.fingerprint} with start date #{cert.not_before_at} and end date #{cert.not_after_at} expired!)"
end
# overwrite content_type for signature checking
@content_type = @mail[:mail_instance].content_type
break
end
article_preferences[:security][:encryption] = {
success: success,
comment: comment,
}
end
def verify_signature
return if !signed?
success = false
comment = 'Unable to find certificate for verification'
::SMIMECertificate.find_each do |cert|
verify_certs = []
verify_ca = OpenSSL::X509::Store.new
if cert.parsed.issuer.to_s == cert.parsed.subject.to_s
verify_ca.add_cert(cert.parsed)
# CA
verify_certs = p7enc.certificates.select do |message_cert|
message_cert.issuer.to_s == cert.parsed.subject.to_s && verify_ca.verify(message_cert)
end
else
# normal
verify_certs.push(cert.parsed)
end
success = p7enc.verify(verify_certs, verify_ca, nil, OPENSSL_PKCS7_VERIFY_FLAGS)
next if !success
comment = cert.subject
if cert.expired?
comment += " (Certificate #{cert.fingerprint} with start date #{cert.not_before_at} and end date #{cert.not_after_at} expired!)"
end
break
rescue => e
success = false
comment = e.message
end
if success
@mail[:attachments].delete_if do |attachment|
signed?(attachment.dig(:preferences, 'Content-Type'))
end
end
article_preferences[:security][:sign] = {
success: success,
comment: comment,
}
end
def p7enc
OpenSSL::PKCS7.read_smime(@mail[:raw])
end
def log
%i[sign encryption].each do |action|
result = article_preferences[:security][action]
next if result.blank?
if result[:success]
status = 'success'
elsif result[:comment].blank?
# means not performed
next
else
status = 'failed'
end
HttpLog.create(
direction: 'in',
facility: 'S/MIME',
url: "#{@mail[:from]} -> #{@mail[:to]}",
status: status,
ip: nil,
request: {
message_id: @mail[:message_id],
},
response: article_preferences[:security],
method: action,
created_by_id: 1,
updated_by_id: 1,
)
end
end
end

View file

@ -0,0 +1,84 @@
class SecureMailing::SMIME::Outgoing < SecureMailing::Backend::Handler
def initialize(mail, security)
@mail = mail
@security = security
end
def process
return if !process?
if @security[:sign][:success] && @security[:encryption][:success]
processed = encrypt(signed)
log('sign', 'success')
log('encryption', 'success')
elsif @security[:sign][:success]
processed = Mail.new(signed)
log('sign', 'success')
elsif @security[:encryption][:success]
processed = encrypt(@mail.encoded)
log('encryption', 'success')
end
overwrite_mail(processed)
end
def process?
return false if @security.blank?
return false if @security[:type] != 'S/MIME'
@security[:sign][:success] || @security[:encryption][:success]
end
def overwrite_mail(processed)
@mail.body = nil
@mail.body = processed.body.encoded
@mail.content_disposition = processed.content_disposition
@mail.content_transfer_encoding = processed.content_transfer_encoding
@mail.content_type = processed.content_type
end
def signed
from = @mail.from.first
cert_model = SMIMECertificate.for_sender_email_address(from)
raise "Unable to find ssl private key for '#{from}'" if !cert_model
raise "Expired certificate for #{from} (fingerprint #{cert_model.fingerprint}) with #{cert_model.not_before_at} to #{cert_model.not_after_at}" if !@security[:sign][:allow_expired] && cert_model.expired?
private_key = OpenSSL::PKey::RSA.new(cert_model.private_key, cert_model.private_key_secret)
OpenSSL::PKCS7.write_smime(OpenSSL::PKCS7.sign(cert_model.parsed, private_key, @mail.encoded, [], OpenSSL::PKCS7::DETACHED))
rescue => e
log('sign', 'failed', e.message)
raise
end
def encrypt(data)
certificates = SMIMECertificate.for_recipipent_email_addresses!(@mail.to)
expired_cert = certificates.detect(&:expired?)
raise "Expired certificates for cert with #{expired_cert.not_before_at} to #{expired_cert.not_after_at}" if !@security[:encryption][:allow_expired] && expired_cert.present?
Mail.new(OpenSSL::PKCS7.write_smime(OpenSSL::PKCS7.encrypt(certificates.map(&:parsed), data, cipher)))
rescue => e
log('encryption', 'failed', e.message)
raise
end
def cipher
@cipher ||= OpenSSL::Cipher.new('AES-128-CBC')
end
def log(action, status, error = nil)
HttpLog.create(
direction: 'out',
facility: 'S/MIME',
url: "#{@mail[:from]} -> #{@mail[:to]}",
status: status,
ip: nil,
request: @security,
response: { error: error },
method: action,
created_by_id: 1,
updated_by_id: 1,
)
end
end

View file

@ -0,0 +1,91 @@
class SecureMailing::SMIME::Retry < SecureMailing::Backend::Handler
def initialize(article)
@article = article
end
def process
return existing_result if already_processed?
save_result if retry_succeeded?
retry_result
end
def signature_checked?
@signature_checked ||= existing_result&.dig('sign', 'success') || false
end
def decrypted?
@decrypted ||= existing_result&.dig('encryption', 'success') || false
end
def already_processed?
signature_checked? && decrypted?
end
def existing_result
@article.preferences['security']
end
def mail
@mail ||= begin
raw_mail = @article.as_raw.store_file.content
Channel::EmailParser.new.parse(raw_mail).tap do |parsed|
SecureMailing.incoming(parsed)
end
end
end
def retry_result
@retry_result ||= mail['x-zammad-article-preferences']['security']
end
def signature_found?
return false if signature_checked?
retry_result['sign']['success']
end
def decryption_succeeded?
return false if decrypted?
retry_result['encryption']['success']
end
def retry_succeeded?
return true if signature_found?
decryption_succeeded?
end
def save_result
save_decrypted if decryption_succeeded?
@article.preferences['security'] = retry_result
@article.save!
end
def save_decrypted
@article.content_type = mail['content_type']
@article.body = mail['body']
Store.remove(
object: 'Ticket::Article',
o_id: @article.id,
)
mail[:attachments]&.each do |attachment|
filename = attachment[:filename].force_encoding('utf-8')
if !filename.force_encoding('UTF-8').valid_encoding?
filename = filename.utf8_encode(fallback: :read_as_sanitized_binary)
end
Store.add(
object: 'Ticket::Article',
o_id: @article.id,
data: attachment[:data],
filename: filename,
preferences: attachment[:preferences],
created_by_id: @article.created_by_id,
)
end
end
end

View file

@ -555,6 +555,11 @@
<g fill-rule="evenodd"> <g fill-rule="evenodd">
<path d="M1 6v4h3l4 3V3L4 6zM11.293 8L9.146 5.854a.5.5 0 1 1 .708-.708L12 7.293l2.146-2.147a.5.5 0 0 1 .708.708L12.707 8l2.147 2.146a.5.5 0 0 1-.708.708L12 8.707l-2.146 2.147a.5.5 0 0 1-.708-.708L11.293 8z"/> <path d="M1 6v4h3l4 3V3L4 6zM11.293 8L9.146 5.854a.5.5 0 1 1 .708-.708L12 7.293l2.146-2.147a.5.5 0 0 1 .708.708L12.707 8l2.147 2.146a.5.5 0 0 1-.708.708L12 8.707l-2.146 2.147a.5.5 0 0 1-.708-.708L11.293 8z"/>
</g> </g>
</symbol><symbol id="icon-not-signed" viewBox="0 0 14 14">
<title>
not-signed
</title>
<path d="M7.317.106c.03.023.058.049.082.077l1.155 1.385a.524.524 0 0 0 .534.166l1.787-.472a.513.513 0 0 1 .627.339c.01.035.017.071.018.108l.082 1.768a.489.489 0 0 0 .33.434l1.737.62a.48.48 0 0 1 .246.724l-1.023 1.477a.468.468 0 0 0 0 .536l1.023 1.477a.473.473 0 0 1-.144.673.52.52 0 0 1-.102.05l-1.737.62a.489.489 0 0 0-.33.435l-.082 1.768a.5.5 0 0 1-.531.465.532.532 0 0 1-.114-.018l-1.787-.472a.524.524 0 0 0-.534.166l-1.155 1.385a.526.526 0 0 1-.798 0l-1.155-1.385a.524.524 0 0 0-.534-.166l-1.787.472a.513.513 0 0 1-.627-.339.466.466 0 0 1-.018-.108l-.082-1.768a.489.489 0 0 0-.33-.434L.33 9.469a.48.48 0 0 1-.246-.724l1.023-1.477a.468.468 0 0 0 0-.536L.085 5.255a.473.473 0 0 1 .144-.673.52.52 0 0 1 .102-.05l1.737-.62a.489.489 0 0 0 .33-.435L2.48 1.71a.5.5 0 0 1 .531-.465.532.532 0 0 1 .114.018l1.787.472a.524.524 0 0 0 .534-.166L6.601.183a.526.526 0 0 1 .716-.077zm-2.903 3.55a.535.535 0 0 0-.757.758l2.598 2.598-2.557 2.574a.535.535 0 0 0 .76.754L7.012 7.77l2.573 2.573a.535.535 0 0 0 .757-.757L7.766 7.009l2.579-2.597a.535.535 0 1 0-.76-.754L7.01 6.252z" fill-rule="evenodd"/>
</symbol><symbol id="icon-note" viewBox="0 0 16 16"> </symbol><symbol id="icon-note" viewBox="0 0 16 16">
<title> <title>
note note
@ -716,6 +721,11 @@
<path d="M13.21 8.62a1.602 1.602 0 0 1-1.59-1.61 1.604 1.604 0 0 1 1.6-1.59h.01c.427.003.827.172 1.127.476.3.304.463.707.46 1.134-.003.425-.17.826-.471 1.125-.301.3-.702.465-1.126.465h-.01M10 6.953a3.172 3.172 0 0 0 4.768 2.76l1.926 1.93.05.047a.37.37 0 0 0 .526 0l.621-.62a.375.375 0 0 0 0-.527l-.048-.05-1.93-1.93A3.17 3.17 0 0 0 13.191 3.8 3.177 3.177 0 0 0 10 6.953z" opacity=".5"/> <path d="M13.21 8.62a1.602 1.602 0 0 1-1.59-1.61 1.604 1.604 0 0 1 1.6-1.59h.01c.427.003.827.172 1.127.476.3.304.463.707.46 1.134-.003.425-.17.826-.471 1.125-.301.3-.702.465-1.126.465h-.01M10 6.953a3.172 3.172 0 0 0 4.768 2.76l1.926 1.93.05.047a.37.37 0 0 0 .526 0l.621-.62a.375.375 0 0 0 0-.527l-.048-.05-1.93-1.93A3.17 3.17 0 0 0 13.191 3.8 3.177 3.177 0 0 0 10 6.953z" opacity=".5"/>
<path d="M0 1c0-.552.449-1 1.007-1h12.986C14.549 0 15 .444 15 1c0 .552-.449 1-1.007 1H1.007A1.001 1.001 0 0 1 0 1zm0 4c0-.552.446-1 .998-1h7.004C8.553 4 9 4.444 9 5c0 .552-.446 1-.998 1H.998A.996.996 0 0 1 0 5zm0 4c0-.552.446-1 .998-1h7.004C8.553 8 9 8.444 9 9c0 .552-.446 1-.998 1H.998A.996.996 0 0 1 0 9zm0 4c0-.552.449-1 1.007-1h12.986c.556 0 1.007.444 1.007 1 0 .552-.449 1-1.007 1H1.007A1.001 1.001 0 0 1 0 13z"/> <path d="M0 1c0-.552.449-1 1.007-1h12.986C14.549 0 15 .444 15 1c0 .552-.449 1-1.007 1H1.007A1.001 1.001 0 0 1 0 1zm0 4c0-.552.446-1 .998-1h7.004C8.553 4 9 4.444 9 5c0 .552-.446 1-.998 1H.998A.996.996 0 0 1 0 5zm0 4c0-.552.446-1 .998-1h7.004C8.553 8 9 8.444 9 9c0 .552-.446 1-.998 1H.998A.996.996 0 0 1 0 9zm0 4c0-.552.449-1 1.007-1h12.986c.556 0 1.007.444 1.007 1 0 .552-.449 1-1.007 1H1.007A1.001 1.001 0 0 1 0 13z"/>
</g> </g>
</symbol><symbol id="icon-signed" viewBox="0 0 14 14">
<title>
signed
</title>
<path d="M7.317.106c.03.023.058.049.082.077l1.155 1.385a.524.524 0 0 0 .534.166l1.787-.472a.513.513 0 0 1 .627.339c.01.035.017.071.018.108l.082 1.768a.489.489 0 0 0 .33.434l1.737.62a.48.48 0 0 1 .246.724l-1.023 1.477a.468.468 0 0 0 0 .536l1.023 1.477a.473.473 0 0 1-.144.673.52.52 0 0 1-.102.05l-1.737.62a.489.489 0 0 0-.33.435l-.082 1.768a.5.5 0 0 1-.531.465.532.532 0 0 1-.114-.018l-1.787-.472a.524.524 0 0 0-.534.166l-1.155 1.385a.526.526 0 0 1-.798 0l-1.155-1.385a.524.524 0 0 0-.534-.166l-1.787.472a.513.513 0 0 1-.627-.339.466.466 0 0 1-.018-.108l-.082-1.768a.489.489 0 0 0-.33-.434L.33 9.469a.48.48 0 0 1-.246-.724l1.023-1.477a.468.468 0 0 0 0-.536L.085 5.255a.473.473 0 0 1 .144-.673.52.52 0 0 1 .102-.05l1.737-.62a.489.489 0 0 0 .33-.435L2.48 1.71a.5.5 0 0 1 .531-.465.532.532 0 0 1 .114.018l1.787.472a.524.524 0 0 0 .534-.166L6.601.183a.526.526 0 0 1 .716-.077zM10.6 4S7.804 5.156 5.638 7.868l-.087-.086c-.256-.251-1.024-.98-1.498-1.189-.576-.253-.953.615-.953.615s1.432 1.25 3.062 2.928C7.963 6.528 10.6 4.708 10.6 4.708V4z" fill-rule="evenodd"/>
</symbol><symbol id="icon-signout" viewBox="0 0 15 19"> </symbol><symbol id="icon-signout" viewBox="0 0 15 19">
<title> <title>
signout signout

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61.1 (89650) - https://sketch.com -->
<title>not-signed</title>
<desc>Created with Sketch.</desc>
<g id="not-signed" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M7.31730677,0.105840662 C7.34739634,0.128701418 7.37467735,0.154740401 7.39862853,0.183460083 L8.55352341,1.56828587 C8.68077561,1.72087303 8.89122527,1.78613917 9.08814095,1.73408525 L10.8752764,1.26166273 C11.1464562,1.18997736 11.4271753,1.34169118 11.50228,1.60052501 C11.5125448,1.63590076 11.5185802,1.67227207 11.5202709,1.708944 L11.6017946,3.47721668 C11.6107773,3.67205396 11.7408424,3.84292293 11.9322064,3.91128508 L13.6689575,4.53171518 C13.932492,4.62585921 14.0661698,4.90608871 13.9675352,5.15762529 C13.9540545,5.19200369 13.936539,5.22481473 13.9153234,5.25543147 L12.8923367,6.73173097 C12.7796188,6.89439717 12.7796188,7.10560283 12.8923367,7.26826903 L13.9153234,8.74456853 C14.0705514,8.96858215 14.0061276,9.27028919 13.7714289,9.41845008 C13.7393517,9.43869976 13.7049757,9.45541782 13.6689575,9.46828482 L11.9322064,10.0887149 C11.7408424,10.1570771 11.6107773,10.327946 11.6017946,10.5227833 L11.5202709,12.291056 C11.5079005,12.5593736 11.2699828,12.7673164 10.9888668,12.7555091 C10.9504457,12.7538954 10.9123395,12.7481348 10.8752764,12.7383373 L9.08814095,12.2659148 C8.89122527,12.2138608 8.68077561,12.279127 8.55352341,12.4317141 L7.39862853,13.8165399 C7.22338484,14.0266733 6.90284969,14.0614247 6.68269323,13.8941593 C6.65260366,13.8712986 6.62532265,13.8452596 6.60137147,13.8165399 L5.44647659,12.4317141 C5.31922439,12.279127 5.10877473,12.2138608 4.91185905,12.2659148 L3.1247236,12.7383373 C2.85354375,12.8100226 2.5728247,12.6583088 2.49772005,12.399475 C2.48745522,12.3640992 2.4814198,12.3277279 2.47972909,12.291056 L2.39820537,10.5227833 C2.38922267,10.327946 2.25915763,10.1570771 2.06779356,10.0887149 L0.331042537,9.46828482 C0.0675080262,9.37414079 -0.0661697902,9.09391129 0.0324647774,8.84237471 C0.0459455161,8.80799631 0.0634609997,8.77518527 0.0846765586,8.74456853 L1.10766329,7.26826903 C1.22038117,7.10560283 1.22038117,6.89439717 1.10766329,6.73173097 L0.0846765586,5.25543147 C-0.0705513951,5.03141785 -0.00612759356,4.72971081 0.228571147,4.58154992 C0.260648262,4.56130024 0.295024334,4.54458218 0.331042537,4.53171518 L2.06779356,3.91128508 C2.25915763,3.84292293 2.38922267,3.67205396 2.39820537,3.47721668 L2.47972909,1.708944 C2.4920995,1.44062639 2.73001721,1.23268363 3.01113319,1.24449085 C3.04955431,1.24610459 3.08766048,1.25186524 3.1247236,1.26166273 L4.91185905,1.73408525 C5.10877473,1.78613917 5.31922439,1.72087303 5.44647659,1.56828587 L6.60137147,0.183460083 C6.77661516,-0.0266733112 7.09715031,-0.0614247095 7.31730677,0.105840662 Z M4.41361229,3.65675097 C4.20461083,3.44774968 3.8657525,3.44774968 3.6567511,3.65675097 C3.44774963,3.86575281 3.44774963,4.20461113 3.6567511,4.41361243 L3.6567511,4.41361243 L6.25490847,7.01176976 L3.69831796,9.58623834 C3.49004601,9.79596695 3.49122667,10.1348231 3.70095507,10.343095 C3.91068347,10.5513674 4.24953976,10.5501862 4.45781171,10.3404581 L4.45781171,10.3404581 L7.01177432,7.7686355 L9.58491757,10.341779 C9.79391887,10.5507803 10.1327772,10.5507803 10.341779,10.341779 C10.5507803,10.1327777 10.5507803,9.79391934 10.341779,9.58491751 L10.341779,9.58491751 L7.76599841,7.0091372 L10.3448103,4.41229161 C10.5530827,4.20256299 10.5519015,3.86370681 10.3421735,3.65543496 C10.1324449,3.44716312 9.79358867,3.44834373 9.58531682,3.6580718 L9.58531682,3.6580718 L7.00913256,6.25227146 Z" id="Combined-Shape" fill="#50E3C2"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61.1 (89650) - https://sketch.com -->
<title>signed</title>
<desc>Created with Sketch.</desc>
<g id="signed" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M7.31730677,0.105840662 C7.34739634,0.128701418 7.37467735,0.154740401 7.39862853,0.183460083 L8.55352341,1.56828587 C8.68077561,1.72087303 8.89122527,1.78613917 9.08814095,1.73408525 L10.8752764,1.26166273 C11.1464562,1.18997736 11.4271753,1.34169118 11.50228,1.60052501 C11.5125448,1.63590076 11.5185802,1.67227207 11.5202709,1.708944 L11.6017946,3.47721668 C11.6107773,3.67205396 11.7408424,3.84292293 11.9322064,3.91128508 L13.6689575,4.53171518 C13.932492,4.62585921 14.0661698,4.90608871 13.9675352,5.15762529 C13.9540545,5.19200369 13.936539,5.22481473 13.9153234,5.25543147 L12.8923367,6.73173097 C12.7796188,6.89439717 12.7796188,7.10560283 12.8923367,7.26826903 L13.9153234,8.74456853 C14.0705514,8.96858215 14.0061276,9.27028919 13.7714289,9.41845008 C13.7393517,9.43869976 13.7049757,9.45541782 13.6689575,9.46828482 L11.9322064,10.0887149 C11.7408424,10.1570771 11.6107773,10.327946 11.6017946,10.5227833 L11.5202709,12.291056 C11.5079005,12.5593736 11.2699828,12.7673164 10.9888668,12.7555091 C10.9504457,12.7538954 10.9123395,12.7481348 10.8752764,12.7383373 L9.08814095,12.2659148 C8.89122527,12.2138608 8.68077561,12.279127 8.55352341,12.4317141 L7.39862853,13.8165399 C7.22338484,14.0266733 6.90284969,14.0614247 6.68269323,13.8941593 C6.65260366,13.8712986 6.62532265,13.8452596 6.60137147,13.8165399 L5.44647659,12.4317141 C5.31922439,12.279127 5.10877473,12.2138608 4.91185905,12.2659148 L3.1247236,12.7383373 C2.85354375,12.8100226 2.5728247,12.6583088 2.49772005,12.399475 C2.48745522,12.3640992 2.4814198,12.3277279 2.47972909,12.291056 L2.39820537,10.5227833 C2.38922267,10.327946 2.25915763,10.1570771 2.06779356,10.0887149 L0.331042537,9.46828482 C0.0675080262,9.37414079 -0.0661697902,9.09391129 0.0324647774,8.84237471 C0.0459455161,8.80799631 0.0634609997,8.77518527 0.0846765586,8.74456853 L1.10766329,7.26826903 C1.22038117,7.10560283 1.22038117,6.89439717 1.10766329,6.73173097 L0.0846765586,5.25543147 C-0.0705513951,5.03141785 -0.00612759356,4.72971081 0.228571147,4.58154992 C0.260648262,4.56130024 0.295024334,4.54458218 0.331042537,4.53171518 L2.06779356,3.91128508 C2.25915763,3.84292293 2.38922267,3.67205396 2.39820537,3.47721668 L2.47972909,1.708944 C2.4920995,1.44062639 2.73001721,1.23268363 3.01113319,1.24449085 C3.04955431,1.24610459 3.08766048,1.25186524 3.1247236,1.26166273 L4.91185905,1.73408525 C5.10877473,1.78613917 5.31922439,1.72087303 5.44647659,1.56828587 L6.60137147,0.183460083 C6.77661516,-0.0266733112 7.09715031,-0.0614247095 7.31730677,0.105840662 Z M10.6,4 C10.6,4 7.80412273,5.15585215 5.63774444,7.86753754 L5.55140868,7.7819143 C5.29513787,7.53084111 4.52720714,6.80110202 4.05313247,6.5929648 C3.47747036,6.34022674 3.1,7.20839783 3.1,7.20839783 C3.1,7.20839783 4.53194541,8.45802624 6.16208587,10.1358979 C7.9633403,6.52815973 10.6,4.7076373 10.6,4.7076373 L10.6,4 Z" id="Combined-Shape" fill="#50E3C2"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,17 @@
FactoryBot.define do
factory :smime_certificate do
created_at { Time.zone.now }
updated_at { Time.zone.now }
transient do
fixture { nil }
end
public_key { File.read( Rails.root.join("spec/fixtures/smime/#{fixture}.crt") ) if fixture }
trait :with_private do
private_key { File.read( Rails.root.join("spec/fixtures/smime/#{fixture}.key") ) }
private_key_secret { File.read( Rails.root.join("spec/fixtures/smime/#{fixture}.secret") ).strip! }
end
end
end

View file

@ -17,12 +17,13 @@ FactoryBot.define do
trait :dummy_data do trait :dummy_data do
options do options do
{ {
'formSenderType' => sender_type, 'formSenderType' => sender_type,
'title' => title, 'title' => title,
'body' => body, 'body' => body,
'customer_id' => customer.id, 'customer_id' => customer.id,
'group_id' => group.id, 'customer_id_completion' => "#{customer.firstname} #{customer.lastname} <#{customer.email}>",
'owner_id' => owner.id, 'group_id' => group.id,
'owner_id' => owner.id,
} }
end end
end end

View file

@ -0,0 +1,37 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIGZDCCBEygAwIBAgIUAfZ9Sb8pCb7RN34x7oUVKZ/ftY8wDQYJKoZIhvcNAQEL
BQAwgZcxHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoMEEV4
YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNVBAMM
C2V4YW1wbGUuY29tMCAXDTIwMDUyODExMzg0NFoYDzIyMjAwNDEwMTEzODQ0WjCB
ozEpMCcGCSqGSIb3DQEJARYaQ2FzZUluc2Vuc3RpdmVAZVhhbXBsZS5DT00xCzAJ
BgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJlcmxpbjEZMBcG
A1UECgwQRXhhbXBsZSBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEU
MBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQDaNxe6VMcsIVG+Y/aNlNsUWzEZvSycDGKH+1AZ2NBjeEyNRuoiBdbosyxk
mPm6fZ4Prcr2ufIPj5K0cS8xPSBGErqv/6QIUELhEupdxh5cIdhBVDIW/EPrbUFw
CyEAT5/W4p1sqOA8nK1DEac5JprXRiWXzyoWX3HhWbhC20Al1cCqTEoc0pqbSocJ
pN7pmi5VpudtdNFtdlyhkeqT/Yep8roERfEdi5NxBtrn8xWpPXG+db30NjXgZZ9n
wbOHpNKD/Cm/63vIRFtIN1AmrHGE51/2NsrxZGrZ0VoPmx8b82jWb6k22b4EUGdH
Vi7UdLFz2MjBOiYfzLeBPD8PScQQ7PqLYRCb7cTfZExazQC8uBeCHoB5HV9or3aB
CYjpI8PkPEi1CBsCc/ZWh9cUeA7ttZQBwSE+uAyqabOWRMaJO14TRWjlfu2jdRuE
bLtuPGkKzv+iHIRl41E2NgcaP42NRl5limanzvATrD2upd22OmdjzjvE2k2ffksp
tDnlisWrmg3TrAfsHL8AJGwdEzyHH/TNoDd82roOi13UNQBIS5gHFEj8SqaeSTlC
PhCWbpQSTwyi04Lamyw3x7yLsPI5QSLnngWdYgTnC0dGvV+Cn5O6svpPoavLzimF
DfMVb45uPyw/u4VSftdeN4U0jkRxPd+nRr9rcOZKllGWDUEkIQIDAQABo4GXMIGU
MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdDgQWBBT8m5pVFWnVMeZ/Hsy5
6eaBAB/qTDAfBgNVHSMEGDAWgBQMLUKtYgxz7600qkVe6yLEMX3YbDAlBgNVHREE
HjAcgRpDYXNlSW5zZW5zdGl2ZUBlWGFtcGxlLkNPTTATBgNVHSUEDDAKBggrBgEF
BQcDBDANBgkqhkiG9w0BAQsFAAOCAgEAkL+wwgHfsFIDfXRPc3TIIUExu1PayiS8
0ohDFPYlMpq9dUlqqANqzb2WC52E4dxi3LCJfjYuqHFmxNta/3iZwrL25JzR1g5g
ByL7lGMwbMIR/LV/noOqXbTSpwzUcpPD+ElZjexseyrj/xwU5BIMfT8cfQ2h3G+1
nMhn7iXxV4c3LpHAbV1eKZAtbVw+Mq4QpM1F6Jd2u9aYChUfbD5HDvihhEEHA0GR
ZSSns2pQpLplneh6eemPPJSvrhp86TEbVBtaEc+oT/bJoSnByHy8RYI3ST+u/oxF
+slxBrWj1Tbwu8AlGKSxYcXRxYdhjP3R477Uu5NyP9dzrcWctLy77GSv3fLy0xpI
SrMu3J3hIdVrZL+/x/kCWQ/u5oy6dI/O4ewXWyWg/r5Ccj/xZhIdHRH7bSKXgqOn
dL2U8vQGZdIuGkHTznCLagX8Tw74LcP9oHUpQM0rj7v4IY/qaWRt9CBUTAt/CN1l
nACYUIwiWirBV9i8kwtikyqc+baZMdX/QyXqjdZBHRWm2ewQM5meA9Sqer+iIiH7
iDVX4DROMYvOx2bfvRNR/X7q1cZHpcoa4cfMGbkYp1vlVsS3BBApbjGUsqoBYxlK
mERsZxk4XPJSeeS1i/Szp94FzKp8qg3YuAx71eJnTZxuzRvnztSufRQyOP6sSbtJ
3fE8GIlZAgYwIjAKBggrBgEFBQcDBKAUBggrBgEFBQcDAgYIKwYBBQUHAwE=
-----END TRUSTED CERTIFICATE-----

View file

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIE6TCCAtECAQAwgaMxKTAnBgkqhkiG9w0BCQEWGkNhc2VJbnNlbnN0aXZlQGVY
YW1wbGUuQ09NMQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQH
DAZCZXJsaW4xGTAXBgNVBAoMEEV4YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlU
IERlcGFydG1lbnQxFDASBgNVBAMMC2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEA2jcXulTHLCFRvmP2jZTbFFsxGb0snAxih/tQGdjQ
Y3hMjUbqIgXW6LMsZJj5un2eD63K9rnyD4+StHEvMT0gRhK6r/+kCFBC4RLqXcYe
XCHYQVQyFvxD621BcAshAE+f1uKdbKjgPJytQxGnOSaa10Yll88qFl9x4Vm4QttA
JdXAqkxKHNKam0qHCaTe6ZouVabnbXTRbXZcoZHqk/2HqfK6BEXxHYuTcQba5/MV
qT1xvnW99DY14GWfZ8Gzh6TSg/wpv+t7yERbSDdQJqxxhOdf9jbK8WRq2dFaD5sf
G/No1m+pNtm+BFBnR1Yu1HSxc9jIwTomH8y3gTw/D0nEEOz6i2EQm+3E32RMWs0A
vLgXgh6AeR1faK92gQmI6SPD5DxItQgbAnP2VofXFHgO7bWUAcEhPrgMqmmzlkTG
iTteE0Vo5X7to3UbhGy7bjxpCs7/ohyEZeNRNjYHGj+NjUZeZYpmp87wE6w9rqXd
tjpnY847xNpNn35LKbQ55YrFq5oN06wH7By/ACRsHRM8hx/0zaA3fNq6Dotd1DUA
SEuYBxRI/Eqmnkk5Qj4Qlm6UEk8MotOC2pssN8e8i7DyOUEi554FnWIE5wtHRr1f
gp+TurL6T6Gry84phQ3zFW+Obj8sP7uFUn7XXjeFNI5EcT3fp0a/a3DmSpZRlg1B
JCECAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4ICAQBkUCBJ2lYcHPpJim1F09xSbP9B
nHhBXZmE8TdOIQF2Y5aJLtt9rGj+XYzypsz35+FGGSchiKFgdKN+PEGgzkKCeEIG
CIHZW2K9fVtMqsAixKbdn0fHWdItdnEkvse3fIt4O2vr6WYP6xJ4MdEFGyevOw3d
4573Gq+khzgdBY7AZDIPsJu28SkESoPw1yzo3R5XV59kGvM67gNijQWu68F6casR
kQWo8vs5TkmzERBredoJoOb6OCpbdj42jbMf9R5uu3fFJtPQqPxE2aLv5dBI6U+e
aPRnYHFOo4AMhIELaiIsXaHVEfiICFGrZtv8goHdkxeB7flwC5m1Ml7jIj/v5/Ib
1s5/x95urE+OIhUmXyr8bifRijxfqQxL0Ol/nbxZx4AjQb07MaJ7PlqatwX2SjQ/
5Sh/Sex44qFLD+lA3+c6hH3yW4q+rcbciiYa9Imih9sflQcT53jWcwomMsRcA8cP
wMmV2K0JBBYcOOHkyT1+L1v1BGWn0sNlHU+ES58OPU1d/IMbbVK7AZghN/CLPrIG
MlfuOmehiV5vnOvUX5pWsTQAF+7tP2Gw/CUN2TRbOb63OZSlWy1xSlzE9jbs7hb2
WrbTH8e5eI3l0cCT1Ecbz+9/Bm8gtozbbEE/yMyok+Y5NJYjwVboCwQ1QYiIr/eU
eSfenFSsad1y7r5stw==
-----END CERTIFICATE REQUEST-----

View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,897152EBDB085F8EFC4E413FBF5A35FD
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
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1 @@
1234

35
spec/fixtures/smime/ca.crt vendored Normal file
View file

@ -0,0 +1,35 @@
-----BEGIN CERTIFICATE-----
MIIGEzCCA/ugAwIBAgIUdRCemO0RlIZ2tZTwO/1W2eeR/eEwDQYJKoZIhvcNAQEL
BQAwgZcxHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoMEEV4
YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNVBAMM
C2V4YW1wbGUuY29tMCAXDTIwMDUyMDEzNDcxMFoYDzIyMjAwNDAyMTM0NzEwWjCB
lzEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBsZS5jb20xCzAJBgNVBAYTAkRFMQ8w
DQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJlcmxpbjEZMBcGA1UECgwQRXhhbXBs
ZSBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhh
bXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC1bJsQfM2d
3xnNCvQRNaj4u4s5/TnXMdQzwb1fkRTOejEzV0qEXWWTewCMqgFenf/PwHsm6dEC
ESfO8aMz3yu8b8kpIBt3H5cdzSAaQ+Vyyv4bDe+o9EGcYzhRgonef7rYEaU+9s0S
qNDUws1XEAqtu77VHG82p99KSe7nL9t+I01R+f7PNkj553O5QoCHWg1I6zfj7s95
lk9x8wHcBdRfyvYpCAkyV357dDvky2v/zHHYOelgAF0MG77kbsxHLlS9IM+GVFsc
pun28LoS4kokO9d7sDhkwSWFYGCQ/jURDtgFl/kf3JYqoCXdGvaTC1cesX9jm7Pu
HqFB7fhXbsKi2U8RmbTQ3iSsrkn/XWEbcOwGWOBmiDdmAAdCd5Fx2ALizviCfeyE
R0FzWstdDolugCGHt+6Ymm+hn84ZJMfe8HpSb/rqupSUgJUYLJCBFAyRGs5KugQA
/h/Zcd8JTh0cg1BCBca7Gqruqp1RyY09v/VYUlvPqyurfsVGSDvB79UPC0jRSt9I
T6ztiQUEeVcwZz0h2a77NW7JhKd5u96+rbxM2JnBKiNLthEaL92FIjSaZ0bpqJ6E
j/2FO3dhxSgX+lNMEnUmXgJ4Sf/pamoHIjr/KBbB4BF19JiGNsMP2Xa6FjwCmiM/
62s7K6N32wa7kniRVKbvkAT0N7117TqsEwIDAQABo1MwUTAdBgNVHQ4EFgQUDC1C
rWIMc++tNKpFXusixDF92GwwHwYDVR0jBBgwFoAUDC1CrWIMc++tNKpFXusixDF9
2GwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAa6/qeDl7R1iv
rRR66oAjjkt9m191fO41c/f+kA8qOeCNKuZRGWHYPRJYg2P72uQFANHawl8jcFlW
3gFNJ/+i7CxEhxeIFxIYX+wFEgqCBZCd1Ao+4i68C4EAVNVmtPxC96aGstzgamg/
qIv70DpLDpTC6ZcD/qHbJQb2Qspsuz1jvkELQ3on77utHEaJcBn6C1qKotRIplWH
OKTczLtCgx/BI5QGV+XjzaJXm34l5LS3fA2Y+f2faSWz6lBjSZnTTxijBQfrMDqr
2h6CkEWniPeEY85Knbh7tdc7l0Q+mtUEXrw+8hrDRu8bVAfeGsx4464gd4ulZrmH
bBVqTxsarhih/UsB37Pk+lAueB5T/aqbr4QJj1mu+hukQcqySUCbl5b8S9sgfbB0
RP+N9OgqRnkLlnds5eG3+XJl4G6h0iWEKP/XapQcf6VBZTvs17AxVnPDvDUKirTG
ecvAj8m07orp33Ng/5obFYxgLaJEBh2bA1NIVvPQzaYxDssp21JOawyUiWEAc9u0
itycRBjSYxp8Q84HSj2Mw0+RQ4LKpclUlBeuN9tKo155lJanGVOm3Dy7QhpI0nxT
LMOTqLLv5EJo+5ok1IUTLBkvtPvFsYVZuauJyDdTUc7fpdILXXO9jGIKcBzf7ima
FglHwSJZSR2WTTsmd6f/9grOUVNt51I=
-----END CERTIFICATE-----

54
spec/fixtures/smime/ca.key vendored Normal file
View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,C883629DF6D2EB2F339DA0E9DDE3A287
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
-----END RSA PRIVATE KEY-----

1
spec/fixtures/smime/ca.secret vendored Normal file
View file

@ -0,0 +1 @@
1234

35
spec/fixtures/smime/expiredca.crt vendored Normal file
View file

@ -0,0 +1,35 @@
-----BEGIN CERTIFICATE-----
MIIGHzCCBAegAwIBAgIUYIratodSaS58JtEjE1cPRBaOADcwDQYJKoZIhvcNAQEL
BQAwgZ4xJDAiBgkqhkiG9w0BCQEWFWV4cGlyZWRjYUBleGFtcGxlLmNvbTELMAkG
A1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGluMRkwFwYD
VQQKDBBFeGFtcGxlIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRQw
EgYDVQQDDAtleGFtcGxlLmNvbTAeFw0xMDA1MjMxMzQ3MTVaFw0xMDA1MjQxMzQ3
MTVaMIGeMSQwIgYJKoZIhvcNAQkBFhVleHBpcmVkY2FAZXhhbXBsZS5jb20xCzAJ
BgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJlcmxpbjEZMBcG
A1UECgwQRXhhbXBsZSBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEU
MBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQDX2iR3ijNCRE9Yv5wa6WZbDehPrAiX9ImVhCTZkn/ZzjfeoIaaBnCcm0NB
7yT6v0E3JCOV1RcY4AIKwD20EkOFMdhTyKs0V7VfljZSppe6+0Imm0WQ4tifC/WE
ADKze/Vv9hynBqAUUVaSpah8VcqnpDxLxbTvsdSPtJ636Fujo42jCnvnHpbbzAs1
cwXmRxUoVVlxwKxA4vCcV0GBSl2sX5RufYIWSaQn5eqcJxaZQ4H82/zl3rfVaYvc
KVf/Ifs9gur7QL3WSuV1zJGfS6bWRRgt5fYWN8GiVGWfSVgHqEtE9V/akukYTNL3
itPjXKYsoLvczefCOWJWAYMHFZrKrUY8HSye/UdiSSq0TD0XrkAtZwXPgcxOR1UA
0BP1yriauVBJAQNpdV3v1nggiGOdQ+7bBLNebVYxi9rMox5NvmV0N8nCKXG3tfNe
tEokN6tAMdq0sRiUwQJwiEO8M5vjPAhqW3sCQorl3+lwS7yVS9HzsV0SWpcdyDfn
gx8EVF/YhRVwLBCRL8U8HNSLWYg4U/Ni3azhOWyvePlrvm+LgEazQ2k68UFPV1hH
oQPkN2EJhHFLalgCKSKzBG+I41fXsIuAjIDMim8gfSVZ9+Ycspq7R2jgBCHeXC4S
J6ancmXfNPvKolIw9zr0yR3YSrVHOJ9INnyrG/eCyWD/0yT9cwIDAQABo1MwUTAd
BgNVHQ4EFgQUH2C76A6xdx+lIt0fi4TqUWTpj4UwHwYDVR0jBBgwFoAUH2C76A6x
dx+lIt0fi4TqUWTpj4UwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
AgEAOJE1qOMwAE8N3mSVLOjNykkwkZK7onDMgdGEAKcX0u1UGrrkx5ITsmJTEb1L
/2aHVTRLUEpcgJAGsKQSPf3ZN4YfVKSADPn8aGMPZaNPe8U5zNJ0IoKzeKh6J47R
NmhCwXPgZcA0PYFn14TNPD054CsWcShpprJpxjnCkScYgMIpdPTsMDwGDIm8vLME
rhV1tMnaLwJghpaeBvIezo4tgUvEThzrzDKJ4s25E7Hu95lHZm4EGFqXl8uyMEqU
NMzhPODWRyznmrj4+Mh4D4/fK5QwPWYj5nyFLcP9ItMPVIQTPJrskrYQODXYVlTk
fVj8HeI+8vQ5Gv4op20KN5Or/l10xlqCKWxP/1VPLMVCKR0eQNHICbS5VNO+eKBz
KFe2mc2VC1Vw9n6WJWMb5PMexR6ZRPPICRRtkIxQzrEjXbci+a8fwYnRHb7amUZN
qGNB/14xa8IAtdQb4l54B/xb/YZPDuxLiUiWF4CUkzER1ITH57yGVYrMjuBO4Hfh
nWT9PMOHSwDu88+ElX+axvgPX9OmW0s0aOiAcgPVba2Q86cWER9ag07xyGPQ7Zgi
f+L8MeemYl0CPDVMPjp+o+gm5eMzOAbakNuVfiNzGYbJYBT4OqurXRKPn6AKFhgg
NkiZz+lwHxJ8b6Tm9xITXQdyMa/6jUOgYECu9RJO4qd38sg=
-----END CERTIFICATE-----

54
spec/fixtures/smime/expiredca.key vendored Normal file
View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,AFFF2A7AF6117991109A4B9D75D38008
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
-----END RSA PRIVATE KEY-----

1
spec/fixtures/smime/expiredca.secret vendored Normal file
View file

@ -0,0 +1 @@
1234

View file

@ -0,0 +1,37 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIGZzCCBE+gAwIBAgIUCSX5LFwjHF203lCsQWh3FmcEo3IwDQYJKoZIhvcNAQEL
BQAwgZ4xJDAiBgkqhkiG9w0BCQEWFWV4cGlyZWRjYUBleGFtcGxlLmNvbTELMAkG
A1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGluMRkwFwYD
VQQKDBBFeGFtcGxlIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRQw
EgYDVQQDDAtleGFtcGxlLmNvbTAeFw0xMDA1MjMxMzQ3MThaFw0xMDA1MjQxMzQ3
MThaMIGiMSgwJgYJKoZIhvcNAQkBFhlleHBpcmVkc21pbWUxQGV4YW1wbGUuY29t
MQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4x
GTAXBgNVBAoMEEV4YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1l
bnQxFDASBgNVBAMMC2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEAu2WQQ8nX2X9JqZwqQi0qiVmu5gn956l63OF47lhJzP7hha7aP2nT
Syv+fNHn+5Td9Bu8VlNFMcGgcEAgtl9ESx5sFMgYjl0zRUNNcUHCMXFQ4deTq6IJ
/WzjOIZxaS15Cy7L7CUPYGhrxhaCCXH1CoR3fX8SzxZDNEUJsHq1MuJln+sodcXT
04UQ4rgvgnv0UGU5T2iQoCP4fhlICyG1iU7OBwYS+ifJDH8EJSSbDrkbZaO18Svk
aYu81s1GBcSPMOJBJRDKwHdj/0QEGY4PuK2xYOE4SkQ31gJAjMVaSCxBv1i/ePgg
n9Dl+Wnlxq9SI9K5OBd14LnrpTYIksIRQ8um6jehR7i1JA04DG+El0qZNJvgZTP/
sVdX11/HdYmRQ/agPNoMlcAxWd7aNJ4uHStElh/P599WnjonoU8MCpiGm3+spnIF
Xdg0PXTMYm1jpixwQj9YKIKSi16ABi77GgknSe+Fsvua4TJWvf0emySnhje0k4pR
fet5vi/uRbUv/qtm4KFSdkZrbBDlNuLOYATlDP9DLHmGlvSfoL6XWktYHKtr14dh
ThhpPayxOCRP7VJtx2lY40YrTJsSPRNTSokVp6Iaopps2Cvmifix6oObsGmfFH2I
vEhrqmv/hDMvQGb3dLmeUiomd5GTG9ThaZGuT6XcsqTVNodsyJAik88CAwEAAaOB
ljCBkzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAdBgNVHQ4EFgQUdgQNLDuAzIMe
B4CsomLEZU8IRZIwHwYDVR0jBBgwFoAUH2C76A6xdx+lIt0fi4TqUWTpj4UwJAYD
VR0RBB0wG4EZZXhwaXJlZHNtaW1lMUBleGFtcGxlLmNvbTATBgNVHSUEDDAKBggr
BgEFBQcDBDANBgkqhkiG9w0BAQsFAAOCAgEAhK4r3vPyg2aV1o7KWG+tZ1OGudJj
KfiGoOiee3yRuZABonb0FxqmPt2wFQ9Z2yk4mDHNmAE1BiiPErAPQ9dzbyR5turP
VvQ6e41khyOR5ZzKfjJtkTAn8iQAVHS4lr3B0jjeNtzpPvCfTX2F0BhI9hO6BU9+
vpMHcm2JdriCUrPMYmoyujib+Dc76dRBOWIJWRu4q0ANvrYQOWiKW/GdMDiRbNVB
Fu31s0fyxdA/TM9FBrk9E0EDpyxskaWULMXK7VBa7GfBD6P/MFdxGbE/HT87KewI
J5G+2x2kCKfzNGKOhcHDegfvX30DiR86NQREnazAXATpMBtlroUn4eWWBOw2Trod
+a+U11ET9t43PXxgk7jp5UwgUqHTNdCMgy1wc0JZw01m6aXS6mfG5NxuCZRgRvUj
LLwzo/wa/lYKTm5t4s9j4B3yNK7BThOKNcsQSKPTWg4eUWFTVPaXI+eN10vbNYZ7
OUWrzm9BMvH6RBGktaJzbJ597D29R56d044T65njVJO3BaZyTWhkp51P47w+BDxX
jSJjutQsNiEaG4KSWhiJfI2ya3lp6u9iNzsfLsmGl2ywWjhyQPGfee894twt9LdU
r0bak4xs76aD5p/BXL9BatXd6almGjv0SxUUjYJ6VBThXjm9//gfhcxtZkWVPfev
WsOFFaZH/kQ7yH4wIjAKBggrBgEFBQcDBKAUBggrBgEFBQcDAgYIKwYBBQUHAwE=
-----END TRUSTED CERTIFICATE-----

View file

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIE6DCCAtACAQAwgaIxKDAmBgkqhkiG9w0BCQEWGWV4cGlyZWRzbWltZTFAZXhh
bXBsZS5jb20xCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcM
BkJlcmxpbjEZMBcGA1UECgwQRXhhbXBsZSBTZWN1cml0eTEWMBQGA1UECwwNSVQg
RGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQC7ZZBDydfZf0mpnCpCLSqJWa7mCf3nqXrc4XjuWEnM
/uGFrto/adNLK/580ef7lN30G7xWU0UxwaBwQCC2X0RLHmwUyBiOXTNFQ01xQcIx
cVDh15Orogn9bOM4hnFpLXkLLsvsJQ9gaGvGFoIJcfUKhHd9fxLPFkM0RQmwerUy
4mWf6yh1xdPThRDiuC+Ce/RQZTlPaJCgI/h+GUgLIbWJTs4HBhL6J8kMfwQlJJsO
uRtlo7XxK+Rpi7zWzUYFxI8w4kElEMrAd2P/RAQZjg+4rbFg4ThKRDfWAkCMxVpI
LEG/WL94+CCf0OX5aeXGr1Ij0rk4F3XgueulNgiSwhFDy6bqN6FHuLUkDTgMb4SX
Spk0m+BlM/+xV1fXX8d1iZFD9qA82gyVwDFZ3to0ni4dK0SWH8/n31aeOiehTwwK
mIabf6ymcgVd2DQ9dMxibWOmLHBCP1gogpKLXoAGLvsaCSdJ74Wy+5rhMla9/R6b
JKeGN7STilF963m+L+5FtS/+q2bgoVJ2RmtsEOU24s5gBOUM/0MseYaW9J+gvpda
S1gcq2vXh2FOGGk9rLE4JE/tUm3HaVjjRitMmxI9E1NKiRWnohqimmzYK+aJ+LHq
g5uwaZ8UfYi8SGuqa/+EMy9AZvd0uZ5SKiZ3kZMb1OFpka5PpdyypNU2h2zIkCKT
zwIDAQABoAAwDQYJKoZIhvcNAQELBQADggIBADS28gWmrzgcXx+ZTFc3EpffNmcx
lulJ31PXsNot2NRMga4mRA5L8GK1uKrLAIq4koaBUGT0vvV46R9zpC+bildfxNGz
5+v7mvIYkpdfFJW0vAHnO4FuUMkNHDvLSVtly+zQD6k1fwrHxCqsr0bKaZE28b5Z
Bf/9mLprifmtSOy0brSGQ/C7C3z4NCvtLHd6Tb53lnBK6WTeoRYKXvFynIN5Guf1
ONCcUK2TIRxjSYLiz7A26SpHGHfgGnjZutJUqKtr2sWhpq/XVZe8tfAWBrMTn4oT
SJAYRQ7iHdr15egpB0Y/SNn5nkcYSsSg+deEzV2pTbxgEOlY/+ti/V1xyBumIFo8
6Taj2mRXZHkzUNqEWB+nG6zvJwqyefTxaDA6Ijw29tFSURxH0j5priAgKJaBzQ5z
LTLfdi/HU92k7ACJxK5tJdDRj1uVUxPg2wS+mZVn3s4qU6wly3Nk8JsnG+WKUQFQ
BU/a00qy/4KjthFm6Tb++I0X7xZO42aMuaVepskQyum7AhTqehyayGo/MhGf1QIs
ouTC8BF7MMBvF2EHEf3TOazbYDoeUS3VHm1wEgjlt500/DiOlFxMWO7JCebRTxHA
NuHxvIwaPOQPP3gLi0IxV1HzG5rPxa66l+pp3M+lU8V+nQuNBvCa10FVgQB+BBrt
5En06ChboN3gVolO
-----END CERTIFICATE REQUEST-----

View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,8CE77F705A91FC4378059C551C7C5A05
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
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1 @@
1234

View file

@ -0,0 +1,37 @@
-----BEGIN TRUSTED CERTIFICATE-----
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
-----END TRUSTED CERTIFICATE-----

View file

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIE6DCCAtACAQAwgaIxKDAmBgkqhkiG9w0BCQEWGWV4cGlyZWRzbWltZTJAZXhh
bXBsZS5jb20xCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcM
BkJlcmxpbjEZMBcGA1UECgwQRXhhbXBsZSBTZWN1cml0eTEWMBQGA1UECwwNSVQg
RGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCfsqLrCIBVQPywMQQglALMjW0/ZVuuLoXmS5t+7ZJW
lQIviL+oL+O3WfVZ+l4pPTvLHu2FmG4x7AKuB8g403L/ietVNJgevWpn7ICSSbg1
5MIwuSMFGKuC3hL9UpYmwqECm7PYl2WKo8+0QqFR8NCs3x+EZ4nbNyUEWjxYRG7P
IyGh/bO7aeKrFEHHe8Jql/ynPedaQ/fKxn6q8opr6x7YTWtPq33truqmBb6V6l4a
6SBJE0Yaw5EJ4FzBa12zVO2BKoDCVuA0IVq8vYDrL34oSCM4zOGyLwLN/TlMtssv
hjqwsV65nyuHCImN6NH/mqOxScVIFcjDbS6VMmx8Q7Sm4LSKsH4nnK34G0plaHZP
O+GpEgqf5TJnUH3VfJKw84aBrXaYrgdfeVjvx12a3dcMMRwv/T9zUgS5PImsOIcK
y6brSBayy5jIZF+cMmspWQV3qgBKHphgi8QFCFjSJvWqx9rbYNGqLG43jVAXAVr1
BGFyY6raX7o2rxSXOdFj/nsrYhlAZn0E7ljiVjHhZzXH4LvlwV28ByvKPwazUTvn
b0GDd95vT2QfqcKxKJUYJzzE49+dmMjNg1U3Rb/3xJyv9RzdhHUw7d9aWOqIOvfF
Y2utBOMSCUkPB9BQbPrB8I9Aq1C6WYu8pDX2e1yU3Jb54wf4hOknVYswId/Gm3zN
ywIDAQABoAAwDQYJKoZIhvcNAQELBQADggIBAHvxYspSNaV/k9ram2S/N+OepSQq
BZh5sQKI/JXqihU6/CEXB48Ogwmg0b4HbpVmZWqgs4XbGediTtj3yq5HVmqQ3518
ZIUH/ZwKn4HSCQyTJ4PmMCVq15E+nqhXGMCuk/4xVTuv4eCqHKHqLvliWLU6Zqy2
5TJKLMOLlfulbN5KkV/2S185pHXDt/IHey6/GISeuIR0t9ev8+3apv7TWLT/aLbn
lJQuHFLBOWmFjk0QF69jcXA8O6wjmJguJA2NjamrjQ0Uy+PXN1IDchEwGmLDKbEv
OcuhkBoV5RV+RPw1VBTavjkmHWT6Mb4NW4Iq+iT/SV/oYNqCmJcFKj4s1qxOvB6A
DxWsbX241nf3SUJDcoKl9eLXPqYZDqoH9PNufuJBaHXwUbicKBSdSbDhNPuk3JOM
jOnLeQYE8yrS27xm83XlB0wP11zSefQ+gfKFjOQUuS1RXpQngSDk6RzusglZUhjn
UJdJhTwucOaamGdgpu+LwvZxiAmj9wM2+r6XJ01+VmoKmc+u0/5Kp29AjkjcaFQn
c5PdrgIRtypE4SNZMniY584QNE0boJ503ygiiXd4WTR58Lbg1ezd9EpQeDsfDP3u
suzS3ChO1JCidk7YhV6BKoSAR7fmRBUefu7jWtY/fOUZnl0F9+WA2lwShtFqYE0j
hLPOcHKMoBEygeCn
-----END CERTIFICATE REQUEST-----

View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,2D01520A669DCCAAC31310846FD3F95A
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
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1 @@
1234

21
spec/fixtures/smime/generate/Dockerfile vendored Normal file
View file

@ -0,0 +1,21 @@
FROM alpine
# faketime dependencies to generate outdated certificates
# see: https://github.com/trajano/alpine-libfaketime#with-simple-command-line-apps
COPY --from=trajano/alpine-libfaketime /faketime.so /lib/faketime.so
ENV LD_PRELOAD=/lib/faketime.so
ENV CERT_DIR "/etc/ssl/certs"
# install openssl
RUN apk add --update openssl && \
rm -rf /var/cache/apk/*
# move base files to the container
COPY config/* /
COPY docker-entrypoint.sh /
# enable volume to generate certificates into the hosts FS
VOLUME ["$CERT_DIR"]
# start
ENTRYPOINT ["/docker-entrypoint.sh"]

View file

@ -0,0 +1,6 @@
# Zammad S/MIME test certificate generation
This folder contains a `docker` image and the required files to generate various S/MIME certificates for testing purposes. These contain CA certificates as regular certificates (1). There is one special certificate that is for multiple emails at once (2). Additionally some already expired CA and certificates are generated (3).
For the CA there are `.key` and `.crt` files. For the certificates the `.key`, `.crt` and `.csr` are generated. Additionally a `.secret` file is added that contains the corresponding pass phrase.
These are easily generated by executing the `run.sh` file. There is nothing more to it except of having `docker` installed and running.

View file

@ -0,0 +1,8 @@
[smime]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectKeyIdentifier = hash
#authorityKeyIdentifier = keyid:always,issuer
authorityKeyIdentifier = keyid,issuer
subjectAltName = email:copy
extendedKeyUsage = emailProtection

View file

@ -0,0 +1,15 @@
[ smime ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectKeyIdentifier = hash
#authorityKeyIdentifier = keyid:always,issuer
authorityKeyIdentifier = keyid,issuer
extendedKeyUsage = emailProtection
subjectAltName=@alt_names
[alt_names]
IP.1 = 192.168.0.23
IP.2 = 192.168.0.42
email.1 = smimedouble@example.com
email.2 = smimedouble@example.de
otherName = 1.2.3.4;UTF8:some other identifier

View file

@ -0,0 +1 @@
1234

View file

@ -0,0 +1,104 @@
#!/bin/sh
echo "Zammad S/MIME test certificate generation"
if [[ ! -e "$CERT_DIR/ca.key" ]] || [[ ! -e "$CERT_DIR/ca.crt" ]]
then
echo "Generating ca.key"
openssl genrsa -aes256 -passout file:pass.secret -out $CERT_DIR/ca.key 4096
echo "Generating ca.crt"
openssl req -new -x509 -days 73000 -key $CERT_DIR/ca.key -passin file:pass.secret -out $CERT_DIR/ca.crt -subj "/emailAddress=ca@example.com/C=DE/ST=Berlin/L=Berlin/O=Example Security/OU=IT Department/CN=example.com"
echo "Generating ca.secret"
cp pass.secret $CERT_DIR/ca.secret
fi
for EMAIL_ADDRESS in smime1@example.com smime2@example.com smime3@example.com smimedouble@example.com CaseInsenstive@eXample.COM
do
if [[ ! -e "$CERT_DIR/$EMAIL_ADDRESS.crt" ]]
then
echo "Generating $EMAIL_ADDRESS.key"
openssl genrsa -aes256 -passout file:pass.secret -out $CERT_DIR/$EMAIL_ADDRESS.key 4096
echo "Generating $EMAIL_ADDRESS.csr (certificate signing request)"
openssl req -new -key $CERT_DIR/$EMAIL_ADDRESS.key -passin file:pass.secret -out $CERT_DIR/$EMAIL_ADDRESS.csr -subj "/emailAddress=$EMAIL_ADDRESS/C=DE/ST=Berlin/L=Berlin/O=Example Security/OU=IT Department/CN=example.com"
echo "Generating $EMAIL_ADDRESS.crt (certificate)"
if [ "$EMAIL_ADDRESS" != "smimedouble@example.com" ]
then
extfile="config.cnf"
else
# special config that contains two email addresses in one certificate
extfile="double.cnf"
fi
openssl x509 -req \
-days 73000 \
-in $CERT_DIR/$EMAIL_ADDRESS.csr \
-CA $CERT_DIR/ca.crt \
-CAkey $CERT_DIR/ca.key \
-out $CERT_DIR/$EMAIL_ADDRESS.crt \
-addtrust emailProtection \
-addreject clientAuth \
-addreject serverAuth \
-trustout \
-CAcreateserial -CAserial /tmp/ca.seq \
-extensions smime \
-extfile "$extfile" \
-passin file:pass.secret
echo "Generating $EMAIL_ADDRESS.secret"
cp pass.secret $CERT_DIR/$EMAIL_ADDRESS.secret
fi
done
echo "Generating expired"
FAKETIME=-10y date
if [[ ! -e "$CERT_DIR/expiredca.key" ]] || [[ ! -e "$CERT_DIR/expiredca.crt" ]]
then
echo "Generating expiredca.key"
FAKETIME=-10y openssl genrsa -aes256 -passout file:pass.secret -out $CERT_DIR/expiredca.key 4096
echo "Generating expiredca.crt"
FAKETIME=-10y openssl req -new -x509 -days 1 -key $CERT_DIR/expiredca.key -passin file:pass.secret -out $CERT_DIR/expiredca.crt -subj "/emailAddress=expiredca@example.com/C=DE/ST=Berlin/L=Berlin/O=Example Security/OU=IT Department/CN=example.com"
echo "Generating expiredca.secret"
cp pass.secret $CERT_DIR/expiredca.secret
fi
for EMAIL_ADDRESS in expiredsmime1@example.com expiredsmime2@example.com
do
if [[ ! -e "$CERT_DIR/$EMAIL_ADDRESS.crt" ]]
then
echo "Generating $EMAIL_ADDRESS.key"
FAKETIME=-10y openssl genrsa -aes256 -passout file:pass.secret -out $CERT_DIR/$EMAIL_ADDRESS.key 4096
echo "Generating $EMAIL_ADDRESS.csr (certificate signing request)"
FAKETIME=-10y openssl req -new -key $CERT_DIR/$EMAIL_ADDRESS.key -passin file:pass.secret -out $CERT_DIR/$EMAIL_ADDRESS.csr -subj "/emailAddress=$EMAIL_ADDRESS/C=DE/ST=Berlin/L=Berlin/O=Example Security/OU=IT Department/CN=example.com"
echo "Generating $EMAIL_ADDRESS.crt (certificate)"
FAKETIME=-10y openssl x509 -req \
-days 1 \
-in $CERT_DIR/$EMAIL_ADDRESS.csr \
-CA $CERT_DIR/expiredca.crt \
-CAkey $CERT_DIR/expiredca.key \
-out $CERT_DIR/$EMAIL_ADDRESS.crt \
-addtrust emailProtection \
-addreject clientAuth \
-addreject serverAuth \
-trustout \
-CAcreateserial -CAserial /tmp/expiredca.seq \
-extensions smime \
-extfile config.cnf \
-passin file:pass.secret
echo "Generating $EMAIL_ADDRESS.secret"
cp pass.secret $CERT_DIR/$EMAIL_ADDRESS.secret
fi
done
# run command passed to docker run
exec "$@"

9
spec/fixtures/smime/generate/run.sh vendored Executable file
View file

@ -0,0 +1,9 @@
#!/bin/bash
set -o errexit
set -o pipefail
docker build --no-cache -t zammad/smime-test-certificates:latest .
docker run --rm -v `pwd`/../:/etc/ssl/certs zammad/smime-test-certificates:latest

35
spec/fixtures/smime/oldca.crt vendored Normal file
View file

@ -0,0 +1,35 @@
-----BEGIN CERTIFICATE-----
MIIGFzCCA/+gAwIBAgIUMmCv8hoMpL1DxnfbdnB7B8toiJYwDQYJKoZIhvcNAQEL
BQAwgZoxIDAeBgkqhkiG9w0BCQEWEW9sZGNhQGV4YW1wbGUuY29tMQswCQYDVQQG
EwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoM
EEV4YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNV
BAMMC2V4YW1wbGUuY29tMB4XDTEwMDUyMzA3MDUwOFoXDTEwMDUyNDA3MDUwOFow
gZoxIDAeBgkqhkiG9w0BCQEWEW9sZGNhQGV4YW1wbGUuY29tMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoMEEV4
YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNVBAMM
C2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtnoR
t1oSnGD2p6EF/RwRH2qrj0crDtVMubda6sls6tO14a/4qQ/za6WcSKRaPdVtsZ1j
r5yK8QaiaSZ4/jmfmuSpUvu0F7rQyhZ+bNI+ibF6YTHe2DGkdjH4rouoC7WEtfLz
saSYvojXOCelelbiMf94w6uDvMCRu5A47AHgFRAYWh3PD/kPuxefd2OYpZBjUVF0
fOs6tkPWpPzt03Xu8RiJP1/UkLk/ZISLvG5VriMOG+KeOMFAz7gDNaGxoKJ7wlUb
A8Ht0FbQ5ZaYaDlmG0ENhnMoM74h6jxbPlRHvuDzAccZfb9m0e+HX9xP5Q8Cp+ib
EMpSe0SBE3N56a7aCPHTiXoC2wYL32rMUhjC2dgLT/UwBDiMiIksDm7W4IQv10l0
GYGvinDBFEE+fVmQF/g0XBJGmTFi4uN+ZcXaUpLQiBi075E89Rwm9+Xrqr9L/fcm
y2GEnwN0KI2wyFnwMDDMRKfZXSMtU9sCEiqZTIXiAfy9t0wzjbG2P+cXh+p07TNv
POTCyaB98tfocIWIgB6GDFXfgZQJLtZN2Qwm1+MfG63OCFY9QCXoiTaja08+ukB8
kZ8TNCzDs2E82D9fl5aldtaSwCuMJMc0cdIzi25SIJzc4UGtUrEFI8Olrk/QUQ+W
/h0OYptIwJGvdwEquVAfQrPDoIPEN0iJeHfNqWUCAwEAAaNTMFEwHQYDVR0OBBYE
FDw9N9kuUQx109fegyN/ZBWPLmYcMB8GA1UdIwQYMBaAFDw9N9kuUQx109fegyN/
ZBWPLmYcMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAC30oxIo
LaQcXt/AS9FyOZ3dD/5ZzynqTyoSEcP1QzEIXdwIxY3nUaqFCiosBzsd7ZmrSA3S
oaWyFYGutZppVtw39OsbJEKKOv5SX03HEJKoOHkbanPLVNBcdVytRGUI+b61VPEt
SVtbLWD3tjF1Pl0HOtYyzy8gZZWUYRD4LBHtUeDIkY6f1XPTZJuFxpvhb+9l+nGq
OYFhclxVtSNokP+/42vHiNgCuN+9XDhkI2nSC1hKHETEASEmXWCAJ1GI1RqDQ8yr
wghe8LDxRI9R2jTwsd6KEIAufxbEksKw1pvvRS0c06i5cAMf9w/dPerOd1sEdE07
iESaWTc73kjmgglakFRumuuOqsUVmoW9S/IMVt5gyX0wQVjNmV6Ic3LKF5tmEi3E
7h0aFRtzQE+88QcldDLnU4hQA1IwGVpsKnohPq7YWi2HTSp6cJTsdB5c8Rl7zRCw
cy3xWOyLDlUxmYJehfwlHQy+Nf2MZ/KPO8a6Sv9IPF9H6Stra3LD41Ac7+pHz2B/
SrGKieCqoY1Moby/nipRbdwF3ExBjOyDUem+VyYZy7ldsCBW0OE8cwb0D87PN/lu
PULhsWi4ZhPV72kQ5IOvQG/qj78tbVvsoxabY+cDvSrb1NA3aaoQC8T+1Q91YpQa
8c1mJgWpM0EAmsUKjGvE3swfKDtSOPndr6vo
-----END CERTIFICATE-----

54
spec/fixtures/smime/oldca.key vendored Normal file
View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,1B90035BC983D129D9910AA0D912DDE2
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
-----END RSA PRIVATE KEY-----

1
spec/fixtures/smime/oldca.secret vendored Normal file
View file

@ -0,0 +1 @@
1234

View file

@ -0,0 +1,37 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIGWzCCBEOgAwIBAgIUIUrCfVRV1i03o1zHmhtNv8XMpBQwDQYJKoZIhvcNAQEL
BQAwgZoxIDAeBgkqhkiG9w0BCQEWEW9sZGNhQGV4YW1wbGUuY29tMQswCQYDVQQG
EwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoM
EEV4YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNV
BAMMC2V4YW1wbGUuY29tMB4XDTEwMDUyMzA3MDUwOVoXDTEwMDUyNDA3MDUwOVow
gZ4xJDAiBgkqhkiG9w0BCQEWFW9sZHNtaW1lMUBleGFtcGxlLmNvbTELMAkGA1UE
BhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGluMRkwFwYDVQQK
DBBFeGFtcGxlIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRQwEgYD
VQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
AOlZ96ydfW6IGP3roFTyqDTs37MAdHH2VyEYU0qxM98HhDcpXn3iNVeyyOTbeCwy
7yw67EdMwukXZ7VQnxeaz37e7n6tYG/S2lIKYZJkNr2kZ66QACfhSN54wH8sz7H4
giwBV1NShdCtdcjUqV1r8srCOIsUGsW4b8W6HqZ6XDHzmkV6N3pJueUrQdWfY1El
7BBgJY6nsTSQzoycEA5PiWxo9b3Br7z34dj7sHvnQmT8qdlkPq9xfT1tiOpWF5Pk
3Xj6lwqSueYVWpCgohcrxuSi8DpZLwAXXjx410e1YuRMDcC6EbIQioePbFDfgcHv
tgluMZkY5JR0q25na16ONuFYx8FOL+7JzIyxvnUZYUQEvuFXaZk5YhxeRjITvNHr
iV4A7iINBkfwLXeo8GDywSK89VxC6g7p435CBBJfg2kE5jHIy2qVdw83zWfWRuhJ
Xg0NEUV7K8ktDL07w5EJOhhaEqUkvSeNSxUbR/eXyRyrs7kl1VLCI+Ug1x/YBRFn
br8NSKohqvv4s4aZ66bF7nkNlLVEZYmvZorL2VGjCGztbw7nEoft8FPDMfMseKiC
i5lhc4B54d93H06HuDG7TenkXfyCB70kmBSZpImpCJVdP8E3scYbys4zSomu1BQy
/CHn/GBVnS2spE27EWEm6vfF3sghJbFjXmW4O761XM0DAgMBAAGjgZIwgY8wCQYD
VR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0OBBYEFGlwE9fYOr/AGCyldJcQvvTz
Td82MB8GA1UdIwQYMBaAFDw9N9kuUQx109fegyN/ZBWPLmYcMCAGA1UdEQQZMBeB
FW9sZHNtaW1lMUBleGFtcGxlLmNvbTATBgNVHSUEDDAKBggrBgEFBQcDBDANBgkq
hkiG9w0BAQsFAAOCAgEAEXAym+igYPgt1pY3T1fgt0TEkzeBE8BY5s/A4Kpse0aU
RtaQ9jowxSF+hg/MtsNaxIZyXwS5bewrdGla/zlpcYd5uAxw7QgH5HpSrbo0yiVa
t9jET9VZO8ErbCHlf46wBduzNh7XUzZSm2sPBnlGL4CdpWbCQPFdqENFeEKiYpvC
g1Qgw/WTBaOmvNOIWVoSWqQDdLGdBCZys5bkR2YtbZzOgVF/eumyH95yk3BchM0A
scIyxWzHvf8Vss3Idp2djMmSI6tm4wQMvRZ3ScdLBtlStz+J0D3UNhV2lTjdewwn
oJ0RRSj58AVZlD4BFQ0GCg+gwsEhH71CWOuyFWtbzxKhdVojNKHkc6FioKnNffym
nge5o8wYuEETBsu2fHgMTSYxn1jOIVQZuHHXtN/BjXAZUZdKiz7jxZuNiZw43dMg
g5diNC0+VzsMEwINFd5/vQ9R1CX91RFXnZZ5MpM6IGYEHJ7QPRmLmxFtGcFi/f/U
lFCoK0nsOCIcWzFX4PJjAKTvWMekrrp09ImL0IRx+2L7RTA9R6x4DG17ZawTYA1L
uUvvVrbSjfmEIttlktEfL7g9xoDBWxsH7GpfBk4SKNg5jgGpeH5GxzQNPBeqwfeB
XH/n30Ym0jW+y0hDKvnPdjcvz0cJYHe4W3/srtqUu1aJmPa8he7jdejJSpkeUSAw
IjAKBggrBgEFBQcDBKAUBggrBgEFBQcDAgYIKwYBBQUHAwE=
-----END TRUSTED CERTIFICATE-----

View file

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIE5DCCAswCAQAwgZ4xJDAiBgkqhkiG9w0BCQEWFW9sZHNtaW1lMUBleGFtcGxl
LmNvbTELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVy
bGluMRkwFwYDVQQKDBBFeGFtcGxlIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBh
cnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAOlZ96ydfW6IGP3roFTyqDTs37MAdHH2VyEYU0qxM98HhDcp
Xn3iNVeyyOTbeCwy7yw67EdMwukXZ7VQnxeaz37e7n6tYG/S2lIKYZJkNr2kZ66Q
ACfhSN54wH8sz7H4giwBV1NShdCtdcjUqV1r8srCOIsUGsW4b8W6HqZ6XDHzmkV6
N3pJueUrQdWfY1El7BBgJY6nsTSQzoycEA5PiWxo9b3Br7z34dj7sHvnQmT8qdlk
Pq9xfT1tiOpWF5Pk3Xj6lwqSueYVWpCgohcrxuSi8DpZLwAXXjx410e1YuRMDcC6
EbIQioePbFDfgcHvtgluMZkY5JR0q25na16ONuFYx8FOL+7JzIyxvnUZYUQEvuFX
aZk5YhxeRjITvNHriV4A7iINBkfwLXeo8GDywSK89VxC6g7p435CBBJfg2kE5jHI
y2qVdw83zWfWRuhJXg0NEUV7K8ktDL07w5EJOhhaEqUkvSeNSxUbR/eXyRyrs7kl
1VLCI+Ug1x/YBRFnbr8NSKohqvv4s4aZ66bF7nkNlLVEZYmvZorL2VGjCGztbw7n
Eoft8FPDMfMseKiCi5lhc4B54d93H06HuDG7TenkXfyCB70kmBSZpImpCJVdP8E3
scYbys4zSomu1BQy/CHn/GBVnS2spE27EWEm6vfF3sghJbFjXmW4O761XM0DAgMB
AAGgADANBgkqhkiG9w0BAQsFAAOCAgEAGoMv3vAwy8cBLr9rE0r02QKLyYHXtbWX
1JbK/UF/yIfXesde3c/mQdqd3zhxb3YDBK6d483C273a1jdC+8k5NfVvDpcbyLaW
/9sDd9VNXk9CrA4VUVvTBUfYXLsShTRRcyWY9TnoTt0eGnT3PTRzbnW6jEgxStd9
WFhh+FEIea5J/FmvKoEUOkN5j6VQveBJoDwFRZTFLsV/vK4DpcDJJ9KRjm67EssP
n473kwPdzKjjODEitpJqjNG4casn9qgKCKu+a10W9smChsMxGE7Ic1yjb3zDZNfE
sBP8rTcLVe8Y4bEljZOe0acWIFWEltk1wrIJ8IBMEREqPUE3bi/MgD0EL9y44REv
+60YMmCO3BKWEKUM2UYJtNMosNKvULEea7Q3hVVgMV2InisIs3MnDFlwuSTtYF5u
ixR08/8ksvpvrL2ybWTOsJDtiZoaBVoVYr2Z+jXuUyXAXl1rfcmMGNzZ3PYqhTPV
KWBpPiQogyCllL3J2Yf7BD2FRSyjnbsm6Do5rdJLLCFrcltrJ9nOCvLWmawIusl7
jymxpxAf/gOsHO3OfOJARhrL2jaSalaY8BcjLuUJCQ7u1zCDLgHnW+/CPMjDphcF
L+2plCWZr5gtkypczMJFw5ZOlK+SwI0TydCoWkQQxLjaWnqoxigsx3jF9W2uCQDX
iJZ6c2DEnLU=
-----END CERTIFICATE REQUEST-----

View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,075058C49FC97E93DC2A6598E450A08C
xskKR5EEormOQAsY17yBq+yojFhO8awIeNtLILVj5fElywccYSasmh3GzMCr+v8G
hHHXaQwzwkJTglCx9dxCeP++ChnKF+05VHbG3i40PR15Fe94jlMvi3VL3c7wmMvy
pOefj4OZkSUsGa84xwSEVmTd3wYZzlwoZiFrY48jp3Lu5Yv/gYFWTCI3lmJSvDCD
GgqEzu2c+gVje8zAE5QQ/1UMtxw+aqYCrLm0YwHvOSpO0mRWHSUsY7QmiSU+598D
IBXpNfubcZDFF3akq34MOxAnP60oCRi/xdePaYg3cg3FZ03OPr+VY9fFGXpl3Z9R
M0dyVNVsIBb0Ou45dgmVxlXK/VJzEMV1QJnjYhQGJ6BguFbXhFITTAljOYzuMuKk
y2p14vDHJXAUFqPBbAMv1Yrq6rX6Tppl8uHHMBDEEvdJr3c18pAb1S7Ghu0nV5U4
DArM8EL22neoNmpr82wG+bQV4j5bQwmcgMYSjhsDrEpt8593w+6OWrOzQHnZX4p/
9M9/Gkk/i7dvAyBmnIIQhH6V9DFq518e9PGgSIrqhjpG4qDZYrO9OCC26AFjYLS7
iOgVfAeVSh8568jZZdJvxe3LUvZh+lALJzo4zCFZb0wuSb8kAuMWZk8JN+NPpJDp
+ICWZtdaMjQjOis1jQ6X17s1qP/yzNwaaXl1xRd/FVhJBV1z14ZGDU0Repu5Pbm2
9nNUZeBzzbn32KCLocRJCfrtLIGD8b2EHXy7EI1qT0t3ssgKSxK1VZyHw84/rYym
84lXpKolMzhfg3pdntuzRKU1KXgBxcUioU7iPvwkNOwtPLBsPV+Q+U/i2pwyXtXI
cwVkPIzSfrQlPkrmx802zIhWtcEkf3mZpzllosG56bxaDJEMSEMQOK+CL0UY8gYk
TFsZZmJ5W9LIwEG37qKq5gMceAFbJZFBOnWykBNZEa9R/rE/tzR7TCvtZ3UrFoOy
lPvWQK8H1A2QuDNGtITkniWxbif6rKlfr8CUNdl0+fsh8smH3ZTizJT7D2Vo6TJm
xjbbS1v3tr7WlUqxhm6fhagn2yiWfkESLE9BFRr+Npo+mGL5P0eYgMJ7xSPw6FyB
gJEhO+qekzZZCez4k7BwMOx5L2w49Q66z/M4HjcGD49wtf0EVJoyfbMxEp+LQJ1F
x0Y4sBeEJurv5zQw7RLyalxiTgqJ7fgEVgfZrLTdYAJgSfNqRU0RQY3rBOmVtW71
6U1TXsvVIcanJdMtPJxhW9AoQaogIXdL2zgEwzjo8rrjuk47fanLfJ/JKpxsYVvP
vK0L6kCJsZjLHlAPQcmRR8V6H9oGqRYKog4spdLE0RJ8mG9yEquGt8a0PTAXO6p5
wUdmb44x77WiLErzZ74DK+14NPI2ae5z8TKouI/cLPBYM7UjZ/Y/SxdLEMJ5TNKR
ECgKdOUywXKtaVQi5TdbxrQHFQ6CPQzqa3N1bvDYo3M5Ww2UEGKnsF5e1euKSgvI
UPnmIH3glGFsTtRzXZUNAf4cMCwQ5EK1mFfCVjIXHEz2FN8QqWt62DK3u+bZI2dB
wLNVtK7LNMS0p1he8gPJnC8ZK5bcVwhGa21cr1yKAKAyU2MdYbBkWUw/C5eqYoEd
SPjyqoWFsC2gEMO4uXGraTXBbHClu9ZqQY6G8DRX9kHIdQ1u6Uh+xbKf3C3gBfmz
Rvpmv3Da/xWA4APgWTaVjkqlnyL5uCN6kHVchIPQrNRany7qmagLemPQSmQXCDCu
285B4UcEWzyxL3KlAqviUD7XyTiN46VWk6Jhdqx1Rz6NACEhFS1/xYKLFoYPuIyv
j/MNnNwy4favgcNrcDkXanLxN8tFG48yCnWDUqP4LiRBh3X4hSCDl8oIGiKSlOE3
Se62UIXEbUERnLQJKX4G/N34EzfBsgI0oN/xsVkpqooDVROwFW3W0x4vz5KLBjS3
qo3sr8N5+Yc3h8leHKr/SFk8Wg5AExletiEW5bJ/1mfHdpdR/ZpVQleVpLOSn+Kj
lPdYWrCddfYE+znI6czryYbJkTAv6OLLyVN1XgUbk6PTpyIds6tqnjIyONQ5kI6r
+7agGYnTyKmR7WKGYjOGt5IPungRFcAnvMwrvdeDSqoSCNF/VgZ2jwFLNjOLeKk6
m1RnIRwUjU4hbprS92tAQMtXEpi7Z/dCYlchSBFrAg31PW5pSwnSIlqYznGOIHDJ
AFl5ky22T0voly1fMFcNIJBNflr0bMOeGn8yDC5qykqf6Q3fkAQDiBeZlyVmAOht
nXoKRn5iZ3DmAe7WKRl4qTaJ2wWITa4JHXShtrYLXesKVPfuWuY5GBtm55VK/HGj
1hHToDxR8L1c0+pAf74whDcBPBR2sZx2T2eKH11FowqEWLF8zjeKC5buBbSPf50+
xEOc0LZrFGnXDFN7u0quvewAGsGZt2uzHyIEvqfr+t+81k95KXJVYBPr2ygjrVBm
npkqbbhKUnLw97pJGkwRq0P7VJt7l912fAKCyzhvDGKfTcsKNfgu6+IglXrqyrXg
1oBoquWhkwbZf9glRw7K5uRW9ygHXmWkusMiSd7LUj84VNAsztUTPImmITdNrKt6
4A1XMGPyYOXHEI3smOXbK22+deaGSNzFY7vSyF7H/RB4IipGlJx2Fe4SoLZVrmNR
qTAovjvqUmcs3uOnzAGtP2JsS5GSAvbQZEarXgNcTj8u3CcWQrMf9/uuluJmeTE0
+f4kC/+hptnBLW97LMfAl608kc2ArSuepGNfzwalnfmwKsDpiC/GQJlUuv0x5IGe
Is5xwkvaykIK0DaDWTdE1RwH3M6UCcbtoX2V3gXulut8BNooIx9pFV6xMF0THUvC
yIrpU0Oe+HRXjz1rJf6TUDZGuy2pPeJZqnfdzwAy8oo8fUm8h+kcEIj5vb4yfn/N
T2prqu5n+CLhkaoi+kkSL7sF5ckCkSyAydYuSRG1DRP7XBynt+Dj+qRedjo/9drl
VtCyZrodLpakgwBuwMVallbZP/ILag87Lbje03GbyWOxGPPRN3yx7Qo+7t0b6kvz
GlYfWGrBMTK8EZFUUfGZMTOJasl/ipKM60a112ncBgzBlLwQ1mEzGFRFud6mKuwx
X4e5PgSQuGxtLFyfjpZL2ZHDeoouss5TNoiKfp1Obid8H2dD2S6IbRtOf6pKPIv5
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1 @@
1234

View file

@ -0,0 +1,37 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIGWzCCBEOgAwIBAgIUIUrCfVRV1i03o1zHmhtNv8XMpBUwDQYJKoZIhvcNAQEL
BQAwgZoxIDAeBgkqhkiG9w0BCQEWEW9sZGNhQGV4YW1wbGUuY29tMQswCQYDVQQG
EwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoM
EEV4YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNV
BAMMC2V4YW1wbGUuY29tMB4XDTEwMDUyMzA3MDUxMFoXDTEwMDUyNDA3MDUxMFow
gZ4xJDAiBgkqhkiG9w0BCQEWFW9sZHNtaW1lMkBleGFtcGxlLmNvbTELMAkGA1UE
BhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGluMRkwFwYDVQQK
DBBFeGFtcGxlIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRQwEgYD
VQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
AMWrCkplNiVerePhBjafapLrl2WwpzP8O1Epf9mAUrh0iMKX2G2Y1ve+JGLHALwU
aLnOOeOutPJKDGykWQ+/zV/8U80JmOLt8LyrTLzPun1I7FqGAkx/hO6skCbDo5er
szqhIx2bhLdS43EeANRx7RdzNWEYw9Eqgmcc3MFxOGIPe54EbnDcm0qzdvIxtNbZ
ll9rBuLlYAzGSs+5+WdbjnxZGhhaAICgmslJWg1Bh8LbuQX1YYEsThq/KBnidBOl
HSPGMDAj4g075T5A5KwhF6JG2sInSVXWjXktAzxUeZGY4f3dsVc3lAchw6W25IPP
ysF8IF3OfO+N+XKZLYZ9x1P+bB1dsdfSUZFUOWRUcpngWPKofkSYjUL0JQQgKCx3
HmwKQBYhgIeJ35eIPPoWwGdvQTqmveyiYd4TqYYP6f+ay7gIPQEtfsF18y6kdfN5
F3gkv2GKBOvfNP86fnrEftMcQLBxAro+5ceF4ENIBm9xWSgjEISMoD9TlMtn8bIr
Kn8p3Zot3KUMG8AT8g1w8sl+43m4hfbgIZFecMtTHGTfTBKO2KBBnb9oNXh8GAyp
QYRN8oUuC72DQShxfJ5nFYYPghDX7Mlmiwt0X32gi2YwpPf7OI+DQtuUhAGOoGr7
oThUY631kASIXSVtDz+pbP2CYwbSlRqEOE+tkps/3nhfAgMBAAGjgZIwgY8wCQYD
VR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0OBBYEFElniL85pHV/jj46LaOKnG4n
s1gwMB8GA1UdIwQYMBaAFDw9N9kuUQx109fegyN/ZBWPLmYcMCAGA1UdEQQZMBeB
FW9sZHNtaW1lMkBleGFtcGxlLmNvbTATBgNVHSUEDDAKBggrBgEFBQcDBDANBgkq
hkiG9w0BAQsFAAOCAgEAbsc1EVFSRrFivUskd1RyHPeYGaPQilru1UKOINKlblaT
5niNK053XLgKgNYNyhmrJiOmIKPnV0iuTzLOjYsQbY0hArtoHYoMjWYwrPEL6cPq
KAcbvnE3Me8KXEDT1K0ysgwbW4jUyN2qFWbM6cEVu+mv7YOAsTt3J56gbRY71cQh
5wYP6qM3AfQ8aY3e18dEW4h7vLZL/VIvs7jW5NjBzJapfzuj4gvXNKobmAOeWXF3
xAVT93dlgEo5EFexizgyUUG2Oeu/TlN2ssTHfNhgSLfmN20Q1PZf1CqCSS+FbFTp
IgKI07cHQZTM5Uk5M+MZKhmJDIWVKIDMOED2XGeITuKXDJjvU6nFnzEdEcwhiT/w
gxn+qcOo5v7HmmOxVXhtBCsCtZPsx/2DEjRUw5jEDvSsV2+HbCws8+Ry5Q4VT7l6
NX8vhsmyXVLBDBGAhBY4HcV+L5FzluacixGdE+eP3ndN3pOOOQ1cMVTFCotYn/IJ
bZH8mCWfLkuPqkemnIWve4Xv1zVPteMroz56g+M2PnoxPqZbBrYyUEWo3RsYmLFi
Vne8VKWl2OwA/dVoxN4Cpr0JAqXPfYfeWA/f/ZJFTEfTDUN9+MYZyI11obcs2qEp
zjcHzyJKbpQUaeaTKqb6JGSXanHCaW8ud7rTTpH4X65xSoFqb4vd077WpkatBu4w
IjAKBggrBgEFBQcDBKAUBggrBgEFBQcDAgYIKwYBBQUHAwE=
-----END TRUSTED CERTIFICATE-----

View file

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIE5DCCAswCAQAwgZ4xJDAiBgkqhkiG9w0BCQEWFW9sZHNtaW1lMkBleGFtcGxl
LmNvbTELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVy
bGluMRkwFwYDVQQKDBBFeGFtcGxlIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBh
cnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAMWrCkplNiVerePhBjafapLrl2WwpzP8O1Epf9mAUrh0iMKX
2G2Y1ve+JGLHALwUaLnOOeOutPJKDGykWQ+/zV/8U80JmOLt8LyrTLzPun1I7FqG
Akx/hO6skCbDo5erszqhIx2bhLdS43EeANRx7RdzNWEYw9Eqgmcc3MFxOGIPe54E
bnDcm0qzdvIxtNbZll9rBuLlYAzGSs+5+WdbjnxZGhhaAICgmslJWg1Bh8LbuQX1
YYEsThq/KBnidBOlHSPGMDAj4g075T5A5KwhF6JG2sInSVXWjXktAzxUeZGY4f3d
sVc3lAchw6W25IPPysF8IF3OfO+N+XKZLYZ9x1P+bB1dsdfSUZFUOWRUcpngWPKo
fkSYjUL0JQQgKCx3HmwKQBYhgIeJ35eIPPoWwGdvQTqmveyiYd4TqYYP6f+ay7gI
PQEtfsF18y6kdfN5F3gkv2GKBOvfNP86fnrEftMcQLBxAro+5ceF4ENIBm9xWSgj
EISMoD9TlMtn8bIrKn8p3Zot3KUMG8AT8g1w8sl+43m4hfbgIZFecMtTHGTfTBKO
2KBBnb9oNXh8GAypQYRN8oUuC72DQShxfJ5nFYYPghDX7Mlmiwt0X32gi2YwpPf7
OI+DQtuUhAGOoGr7oThUY631kASIXSVtDz+pbP2CYwbSlRqEOE+tkps/3nhfAgMB
AAGgADANBgkqhkiG9w0BAQsFAAOCAgEAOBxGS8NkStWWbcDfiuapX1XB49TCpfNZ
23ElMQ7T0vmfg/rQox1UiHPxLFlaJtdz9BoUT2PAv8aN6GCfzafGvxRwf34+EMxH
4YmekUba7Dp9xIdpApEsxA7OtXwMTgL2I47lUR4d1UI4UL1JWhAASAP2ZRiH69AH
Bkch4VFGWQE9f3F3k3oODe+yyQYeGhOvfoUrFLu05JQexYUjGjP3EVN2EVuOJLgW
w15m2wEjJk1CBptAl4AWWCKAvgwvwzHvzkaooUDZyZ2Q/rKeaM4zBu3/8/SXc7lQ
xFLfzvBuZIQX72o6d3NMAVDoQHHpi1PFgLMbbTkaLvzRzF4oLEMqQSBSa4id1uFf
7YYRop5Fu2UdyUX+dyDPZfVCJwIskdOE+AXiIlxDB/VpA1AGVDRwYPJIMjSsCr9m
xybrCZzYzVyWo5um5pVfRaJckcM6XxM60bigLPqietv9FUGfGfTlDHyRbpqJKYZ9
azgR6QUg5PZQOF6V+iblZEsKxHpqqQT8UPBjyOH5qwq+mCbW4/kneSORPZOposnP
MHZH9lRZ/1LXM5YFrDaFMicKI/h9rRTtFMlH/dAzrvVmz+o5HXew30UipYbZOXZv
1qqvrrW/a8SwMsalEQUHDAnZe8BVI0sLUfOonaXRfzh1CwO7DIWw0XoHaYBkwwxw
bUDcHE3gKFM=
-----END CERTIFICATE REQUEST-----

View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,422646293BBDFBBD651E2D08160A9FE1
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
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1 @@
1234

View file

@ -0,0 +1,37 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIGVDCCBDygAwIBAgIUAh6m+t/Iz8s0i11uzqr7kDKyFewwDQYJKoZIhvcNAQEL
BQAwgZcxHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoMEEV4
YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNVBAMM
C2V4YW1wbGUuY29tMCAXDTIwMDUyMDEzNDcxMVoYDzIyMjAwNDAyMTM0NzExWjCB
mzEhMB8GCSqGSIb3DQEJARYSc21pbWUxQGV4YW1wbGUuY29tMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoMEEV4
YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNVBAMM
C2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtUtb
zV02dBuQuR5Ef4zJAOTPMDw1DNl/GkY1MstUpoV2jjJeB1cDj8oq1RHDwBBVNsaL
4BT9pnCmy8YG0JITR85IBmWB454PSVX9lQHpBXwAihj3B/DjGV0phdo+FuYo3c7B
EygQk+RLKvD0jW/EhZ3dYw/lIU2iV+v3kBMi2R50RL5aEyRgp3/QlsViUWfJgnZn
MEHRtFLP6s/NbM6FkPZoMR36jJVL5xVn5I0+RzzsLTbaWWV6hxC2mDh16aBjcwkW
vJXpuFx/HpXMvLOjTgWssToifbqz2SE7Q4ssHnof7Mx6XD+MjCj+sbKoMbfWLSM0
LUNBqeXhSxGDkT78C7rHzrfnRcqsp2jFpdeMBRRgEYe/2lIfrY0IKQWmfSOr6LOd
9Cs5VxG06nAZ8fF2FM6dw7DqbGXJ2kbD06yc9T9wmdU/TLNuVI4mgTLEojCHUTXG
pnfZtj8JH22lcsRglT3TmQX78UAdXWiyrPt/NoukLbeTTpKqQ2FsfS77N/B4V34/
uu76y+opnRJiYUD+6R4q/wx5dISRyZjmfbNPLuZjXXEyckVIs2n3YfGYP1F+uDIr
UU6wRLlzBaO6rytzY2IAybp+sMIprs+j63LFMBBnnjBz3WBoE4DVnE6tKEGcDcyT
G27+9/lOsBVKIwpbuTi8PmEgaX6P123/069JMEsCAwEAAaOBjzCBjDAJBgNVHRME
AjAAMAsGA1UdDwQEAwIF4DAdBgNVHQ4EFgQUwdO+DOI19I8VZKUWNb+0CiehEYQw
HwYDVR0jBBgwFoAUDC1CrWIMc++tNKpFXusixDF92GwwHQYDVR0RBBYwFIESc21p
bWUxQGV4YW1wbGUuY29tMBMGA1UdJQQMMAoGCCsGAQUFBwMEMA0GCSqGSIb3DQEB
CwUAA4ICAQCFMaaAoAKMkNd8PhdR0/x+OHo/GXKPzy1mDs82SUx50z3CP4ZeaNpY
y13As8kkuy9apHJuOi3gCzSzJ7tWoSHObl++1knXt+0BVTDo4fAGD3+YZxohcGvZ
ua0uH0Wo38xW6fyNfzuNjCvbDaxW7eGNyUG8Zk6YUNHW9O8M3JzdwvPdBhfrnadN
tzxrClIziA2Z3JZODiSofnhkF0jzFotqSA+pA5lX9SnfOEW2CN20cV4YIKaErau5
r1qvMe6W+PecyFGA2Ad9C9JvhKx9f14HqKMwM2MviqkAsjac7OzFrZc+Gs3lADiU
p7X9owpj+oVCGxQeBr2wwhfrzzY9emIF8oSVrFXlk9sQubGpH5R1OYBm2B16Qd0K
O46pMRq2flUnyBNqRwrCq6Mk4qsxOs6sn6dUVBiMyL0wqKlDIeYYCg9VTAblzDcj
2ipwzFmDz+wHZHHnLyuGqEId8XmpVtWiUOFZ7BfGpEPFrna8HcV6KOd+yydYmQr0
6J8f/GnxF2qA6aZFxTFmyPt6rQ+I+deitY4RUGXm+LkXNRzR4wq5Bu+onijk8QWi
ZPhQ7ogwHgkoifMi5kzgUMz/2jF0eS9rBRgX2P9CttaKqRfD4H3hqYYxnjcGWxnZ
iRXhcgQlIAswjM8wJpeRpldOTnoB/xSJ67G6WdL4rpdP1Bh/7uZe1TAiMAoGCCsG
AQUFBwMEoBQGCCsGAQUFBwMCBggrBgEFBQcDAQ==
-----END TRUSTED CERTIFICATE-----

View file

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIE4TCCAskCAQAwgZsxITAfBgkqhkiG9w0BCQEWEnNtaW1lMUBleGFtcGxlLmNv
bTELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGlu
MRkwFwYDVQQKDBBFeGFtcGxlIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRt
ZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBALVLW81dNnQbkLkeRH+MyQDkzzA8NQzZfxpGNTLLVKaFdo4yXgdX
A4/KKtURw8AQVTbGi+AU/aZwpsvGBtCSE0fOSAZlgeOeD0lV/ZUB6QV8AIoY9wfw
4xldKYXaPhbmKN3OwRMoEJPkSyrw9I1vxIWd3WMP5SFNolfr95ATItkedES+WhMk
YKd/0JbFYlFnyYJ2ZzBB0bRSz+rPzWzOhZD2aDEd+oyVS+cVZ+SNPkc87C022lll
eocQtpg4demgY3MJFryV6bhcfx6VzLyzo04FrLE6In26s9khO0OLLB56H+zMelw/
jIwo/rGyqDG31i0jNC1DQanl4UsRg5E+/Au6x86350XKrKdoxaXXjAUUYBGHv9pS
H62NCCkFpn0jq+iznfQrOVcRtOpwGfHxdhTOncOw6mxlydpGw9OsnPU/cJnVP0yz
blSOJoEyxKIwh1E1xqZ32bY/CR9tpXLEYJU905kF+/FAHV1osqz7fzaLpC23k06S
qkNhbH0u+zfweFd+P7ru+svqKZ0SYmFA/ukeKv8MeXSEkcmY5n2zTy7mY11xMnJF
SLNp92HxmD9RfrgyK1FOsES5cwWjuq8rc2NiAMm6frDCKa7Po+tyxTAQZ54wc91g
aBOA1ZxOrShBnA3Mkxtu/vf5TrAVSiMKW7k4vD5hIGl+j9dt/9OvSTBLAgMBAAGg
ADANBgkqhkiG9w0BAQsFAAOCAgEAo/nttSsH76fEfcpRq1WkYqvvi8ZEOPa4wehN
CqRQP2oiVuZyrDVFiDboyqAoCd0+AfIe5UQFaQ/PW1CFeVBRFStPJWxKanX/wlHA
vOyLxsH4jgDoIzH/HOMWlpUb7jaarGhkLxYJwgDoM0YznDGGZPb8GiewvL3psyPf
SKQAUWc9tVVdg0D9WhqSoseP860azx6dvKgisP2HDbZHYJkdIfCjYl6N913vhLKa
tg+FcT8DFqepH1LBUpi6Tj2SI2OYCgioY9mOG7jZn8EEYl1RH2GKj6uGaBULINBr
fWtWFsLkadnMFuR+6oIOHnisHdGNWZqJvy1YsEb/mu4yR27cgGmud8WSpeBRWPVa
+OUR1DnJgTLTcJLYnmIRKRloND58mqiswWb/IHxQgGu2v7rAYy4IxGapf+bsybVO
fgjk30yNKM2yH3ctos0yijYmt5Yj7k4sEFQl635Nwsz20qreQJ13pCQBmMg3xFNU
xpioO8PJFLrXVTQzv8BU5a8F26izDzM2RDVG7yhgrGoQYm66L6MEf5db/SNtx19I
Nmtepqdlj8vQ9OIK+MDzTT0UVEiUQJWm38lKjXFan+o6h3NkYjB+XHzLpU8q6azn
VTDmduZqCjuDU8woKWRAw95PrB3lW3TnMqnux5Ls1811tUyN1UM+JFG0EqVkEPG3
nnV42u0=
-----END CERTIFICATE REQUEST-----

View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,C02E7FD1CD5C829F69D753D19B84384A
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
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1 @@
1234

View file

@ -0,0 +1,37 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIGVDCCBDygAwIBAgIUAh6m+t/Iz8s0i11uzqr7kDKyFe0wDQYJKoZIhvcNAQEL
BQAwgZcxHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoMEEV4
YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNVBAMM
C2V4YW1wbGUuY29tMCAXDTIwMDUyMDEzNDcxMloYDzIyMjAwNDAyMTM0NzEyWjCB
mzEhMB8GCSqGSIb3DQEJARYSc21pbWUyQGV4YW1wbGUuY29tMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xGTAXBgNVBAoMEEV4
YW1wbGUgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNVBAMM
C2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAshnv
h0UmOnz+vUBfB6baNJRjihj9amSqMRQpQLDOUVOMwU5kaHIKiFZ2nU00eLzB7eRF
/UEO7rpFILoq49TyZ+LogpH2Z11ZY4hw6ZVcX0qJ3Aq6X4Huqt0plq4BPdBO8Mdn
dgcgGU94+wKRFWFrL7GiiZMFbc0zZfaIMJY35mhWJfc0Sj8Y6tXpfSQHP9WANPII
8l1YYybv/8nCJCZtxnERTlHoFXay5IX9nr0WSGL+uv038dqClModT3ORp23jy07w
nXmWRURXqjBOb0ZbH0YXrj1axi0vc42E1cBUFLzhxDuD97h7T8a/9QbY8wJ5fKcy
pMU8DZZeMteMbQZBqVY53c42iqj8dkVkvoqVmtTvGbUy6gxsQHkhoZHLFgrWJdLr
YPIBev1DrsZwECgPfkaVn8tFnJpehxptkqONXaz1cp2sbI2oADAlnwK4yeWEVbTs
tKIULzSJidYhBoK7bsede3SsMnGWjwzPEfIQxQj0EpFQEMA+0Egy6l4OQ/96AAMp
tr5oap4yt+N1cpRHoIj8bLg7zzoAIgNceXM4+zPDeU7oa+6DwVM0zB4PnvXvh9gn
W5LKrZZekDgCSEpmehBYReJLbsUoGDCWJ6U5skRBDThsV/On4p05psKfKtNR4fzS
hco1kL06GlXrafWp7wPoh/aLHS9xxzf3YZ3KdvMCAwEAAaOBjzCBjDAJBgNVHRME
AjAAMAsGA1UdDwQEAwIF4DAdBgNVHQ4EFgQUcy/mPtRlG+eTit/lAYQkcymZNCUw
HwYDVR0jBBgwFoAUDC1CrWIMc++tNKpFXusixDF92GwwHQYDVR0RBBYwFIESc21p
bWUyQGV4YW1wbGUuY29tMBMGA1UdJQQMMAoGCCsGAQUFBwMEMA0GCSqGSIb3DQEB
CwUAA4ICAQAMdXmNlVP8XRs6kYF2iHZnvf0Po5RWI8/qM+3s5Ljd4TyvIM8T/s/v
b7ayKJlOzZ4c5o+DE65kTDRT6LRKhWHgjQ8jzAXEb71KK1fdK+ZQ+p+vgyIOmWq6
J0gqcsX9V77cx/Gf2NSNeVPAONggqToapCXyI16uHnaiPMx/Qf4ivXmvaTNw3bVs
U5hqYrLcTxQYR03DgahcGj/ukWdtkpidLz0ex3xpgeiA0Ca0ucExrsDCWv/I/JS4
KHRTxkI9TMSR28KpC3uI7m+OLMohTTNGD8dcD8kIiMBL6Q8DvXYs2aYN4ZBEAxnQ
qcgWYfBkmnONm2Ze3hXBwaJDFd87mXqMpAY+Sck6aRENxG+vj255VRI7rTgw19hM
G6EEbu9pwOfpmVmrkTmNByy0gXPXLcq0zqPkSsmdPEUdj7tbVAhpnhxW7hPfr7HJ
O7uc29UTn7Oby9pZkbAvLtJuPidQY69OpNsY878h8UBbCqo4unuZqLO+7PXrfGn2
T4suSBLUznInTEgsHJNxoKXxTcpXaMwts7DsCMl9KsdF9ea0sVZhGUZ8Yqfxu/eX
4zV3UiapXRl6mS9FCSe7CLArxok853z8RlbDjS5M0wmKvRnoYmQi0Wz6E/hN/uMW
Qs6R7xOlxvkQrLkbPPIKnuP72xOWSGPY8AU2Hu9AfYNkhZ30Lyo6mTAiMAoGCCsG
AQUFBwMEoBQGCCsGAQUFBwMCBggrBgEFBQcDAQ==
-----END TRUSTED CERTIFICATE-----

View file

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIE4TCCAskCAQAwgZsxITAfBgkqhkiG9w0BCQEWEnNtaW1lMkBleGFtcGxlLmNv
bTELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGlu
MRkwFwYDVQQKDBBFeGFtcGxlIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRt
ZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBALIZ74dFJjp8/r1AXwem2jSUY4oY/WpkqjEUKUCwzlFTjMFOZGhy
CohWdp1NNHi8we3kRf1BDu66RSC6KuPU8mfi6IKR9mddWWOIcOmVXF9KidwKul+B
7qrdKZauAT3QTvDHZ3YHIBlPePsCkRVhay+xoomTBW3NM2X2iDCWN+ZoViX3NEo/
GOrV6X0kBz/VgDTyCPJdWGMm7//JwiQmbcZxEU5R6BV2suSF/Z69Fkhi/rr9N/Ha
gpTKHU9zkadt48tO8J15lkVEV6owTm9GWx9GF649WsYtL3ONhNXAVBS84cQ7g/e4
e0/Gv/UG2PMCeXynMqTFPA2WXjLXjG0GQalWOd3ONoqo/HZFZL6KlZrU7xm1MuoM
bEB5IaGRyxYK1iXS62DyAXr9Q67GcBAoD35GlZ/LRZyaXocabZKjjV2s9XKdrGyN
qAAwJZ8CuMnlhFW07LSiFC80iYnWIQaCu27HnXt0rDJxlo8MzxHyEMUI9BKRUBDA
PtBIMupeDkP/egADKba+aGqeMrfjdXKUR6CI/Gy4O886ACIDXHlzOPszw3lO6Gvu
g8FTNMweD57174fYJ1uSyq2WXpA4AkhKZnoQWEXiS27FKBgwlielObJEQQ04bFfz
p+KdOabCnyrTUeH80oXKNZC9OhpV62n1qe8D6If2ix0vccc392GdynbzAgMBAAGg
ADANBgkqhkiG9w0BAQsFAAOCAgEAo8vNeH4f/+3vSI8cs/ZKSkq8kkrmYdqFKuJh
cQK7XoE3bgRB0ahKFoR9vRTE+l9EZZEhQPzevlV44RXmZ4z4KVmm7uLHndaEzW3h
Pe/gQxXO+N9DJKYYtzFij9D/fevWz55aUtgrQg5CrF91B7kZVILWxNNX4EObwvqF
CmaIbOU1poGw2lI/weiGe4bcAbww9c4rNsXaxgqxSpWrtHGvAnF2JDayWVREJgi3
xXtCrh7icg8uAzvTLHzUUho/yABv+HhgAZvBwelmD89QW8AUBwtYxyEEP/LQOgcq
VOGJb89rIHJzOHUZTF+dtEfEcjarxghlw5TcoMwrCA9sc49QrS8ksJYkpMKyG5EC
Sjyjk8S7tdm7TvHJ13EP14770ZTa1Rrpo1ENfOkmqbxbjzuQ2RRxRRunjGVwbIsX
+3FBNMRb6bo/kv2D5NYBahQA/KVHTSfZpX34P3b1XawmP95/jqW2fMyXZ5LGEJ57
hw97dSNA5RBb4Dgd6ompmstaT3U7iLqFgnJq5Br60YLJASm0f0ou8ock0hoJva3y
8XA0687jDGmtp7wWt3GQCc06SZMtBFMrJIezih32C1V/8O8b4oRoChV+2DovZz48
QpMOzXHi0hq1D70vw7kVOkeekMTOj3Pwl4e2nXgjwI3gj29bel2vNN7QkGDQw4RD
Yhv55HQ=
-----END CERTIFICATE REQUEST-----

View file

@ -0,0 +1,54 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,E635B30D63879480FEACF294E0B57BB7
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
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1 @@
1234

Some files were not shown because too many files have changed in this diff Show more