as2 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a467f304fd7955e9f787078b8bbda6277e111e84e75d2cc02c935d6ccc00916
4
- data.tar.gz: b75996e0b5064d1b4133f9ed8db0b9f629cb44746ade335edcd3a2fa04de0edf
3
+ metadata.gz: c823318d35a8e64297b050461d423414e07951268caa8fa1565fb5df4068b34f
4
+ data.tar.gz: 23322af75cf03f24e6a5df4d6d9b17e54ebdacd5a6569859a399cd1629f74735
5
5
  SHA512:
6
- metadata.gz: b8b50c0291eed98d9f74333e094bf1a59cf4bedb987592082dddc04118e319dd85121f8434391fb473783320b6388ec836d0fe54901b02b8c3cdf70f95eb93b6
7
- data.tar.gz: db4e30dba47bd613b3b9b5e0e47d33951e527a31249af79ce7f2073c66035cc9a3aa3a8ba5a88c0163b4e06eec814d6ac2bf48ee060935cc22ec57762bdd2b10
6
+ metadata.gz: a81d120d47bb35d6be109ea7dc873757b3e6f54b4236383a52234d57509cd9ad205beecf0e07faf7965ea5d1a5182da019868e4202ef2eac3c4aee133800b517
7
+ data.tar.gz: 4367841d4bcb9f3376c3ba963a247b0e9036e5e6dae011d2819bd646f4864e9d4ffa4cd3da0decb8f7104913e70ef185ee050fd004b96063b95894a36710466f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.12.0 February 16, 2024
2
+
3
+ Allow configuration of which base64 encoding scheme to apply to outbound message bodies.
4
+ Improves compatibility with some versions of MuleSoft. [#36](https://github.com/alexdean/as2/pull/36)
5
+
1
6
  ## 0.11.0 September 14, 2023
2
7
 
3
8
  * Allow configuration of which encryption cipher to use when sending outbound messages. [#35](https://github.com/alexdean/as2/pull/35)
data/README.md CHANGED
@@ -14,23 +14,25 @@ and with [OpenAS2](https://github.com/OpenAS2/OpenAs2App).
14
14
  These limitations may be removed over time as demand (and pull requests!) come
15
15
  along.
16
16
 
17
- 1. RFC defines a number of optional features that partners can pick and choose
18
- amongst. We currently have hard-coded options for many of these. Our current
19
- choices are likely the most common ones in use, but we do not offer all the
20
- configuration options needed for a fully-compliant implementation. https://datatracker.ietf.org/doc/html/rfc4130#section-2.4.2
21
- 1. Encrypted or Unencrypted Data: We assume all messages are encrypted. An
22
- error will result if partner sends us an unencrypted message.
23
- 2. Signed or Unsigned Data: We error if partner sends an unsigned message.
24
- Partners can request unsigned MDNs, but we always send signed MDNs.
25
- 3. Optional Use of Receipt: We always send a receipt.
26
- 4. Use of Synchronous or Asynchronous Receipts: We do not support asynchronous
27
- delivery of MDNs.
28
- 5. Security Formatting: We should be reasonably compliant here.
29
- 6. Hash Function, Message Digest Choices: We currently always use sha256 for
30
- signing. Since [#20](https://github.com/alexdean/as2/pull/20) we have supported
31
- allowing partners to request which algorithm we use for MIC generation in MDNs.
32
- 2. AS2 partners may agree to use separate certificates for data encryption and data signing.
33
- We do not support separate certificates for these purposes.
17
+ RFC defines a number of optional features that partners can pick and choose
18
+ amongst. We currently have hard-coded options for many of these. Our current
19
+ choices are likely the most common ones in use, but we do not offer all the
20
+ configuration options needed for a fully-compliant implementation.
21
+
22
+ https://datatracker.ietf.org/doc/html/rfc4130#section-2.4.2
23
+
24
+
25
+ 1. Encrypted or Unencrypted Data: We assume all messages are encrypted. An
26
+ error will result if partner sends us an unencrypted message.
27
+ 2. Signed or Unsigned Data: We error if partner sends an unsigned message.
28
+ Partners can request unsigned MDNs, but we always send signed MDNs.
29
+ 3. Optional Use of Receipt: We always send a receipt.
30
+ 4. Use of Synchronous or Asynchronous Receipts: We do not support asynchronous
31
+ delivery of MDNs.
32
+ 5. Security Formatting: We should be reasonably compliant here.
33
+ 6. Hash Function, Message Digest Choices: We currently always use sha256 for
34
+ signing. Since [#20](https://github.com/alexdean/as2/pull/20) we have supported
35
+ allowing partners to request which algorithm we use for MIC generation in MDNs.
34
36
 
35
37
  ## Installation
36
38
 
@@ -48,6 +50,87 @@ Or install it yourself as:
48
50
 
49
51
  $ gem install as2
50
52
 
53
+ ## Configuration
54
+
55
+ Configuration objects need to be initialized for the local system and once for each partner.
56
+
57
+ See scripts in `examples` directory for more usage info.
58
+
59
+ A a certificate can be specified as either:
60
+
61
+ * a string path to a file containing a PEM-encoded X509 certificate
62
+ * or an instance of `OpenSSL::X509::Certificate`
63
+
64
+ A private key can be specified as either:
65
+
66
+ * a string path to a file containing a PEM-encoded private key
67
+ * or an instance of `OpenSSL::PKey::PKey`
68
+
69
+ ### Local System
70
+
71
+ Supported options:
72
+
73
+ * `name`: AS2 id for the local system. (Used as `As2-From` in outbound messages.)
74
+ * `url`: URL of this system. Mainly for informational purposes.
75
+ * `domain`: DNS domain name of this system. Mainly for informational purposes.
76
+ * `certificate`: Certificate used for signing outbound messages.
77
+ * `pkey`: Private key used for decrypting incoming messages.
78
+
79
+ ### Partners
80
+
81
+ Supported options:
82
+
83
+ * `name`: AS2 id for this partner. (Used as `As2-To` in outbound messages.)
84
+ * `url`: URL to POST outbound messages to.
85
+ * `certificate`: Certificate to use for both encryption and signature verification.
86
+ * If this is specified, it will be used for both `encryption_certificate` and `signing_certificate`.
87
+ * `encryption_certificate`: Certificate to use for encrypting outbound messages.
88
+ * Only required if `certificate` is not set.
89
+ * `signing_certificate`: Certificate to use when verifying signatures on incoming messages.
90
+ * Only required if `certificate` is not set.
91
+ * `encryption_cipher`: Cipher to use when encrypting outbound messages. A default value is used if this is not specified.
92
+ * Call `As2::Client.valid_encryption_ciphers` for valid options.
93
+ * `tls_verify_mode`: Optional. Set to `OpenSSL::SSL::VERIFY_NONE` if partner is using a self-signed certificate for HTTPS.
94
+ * `mdn_format`: Format to use when building MDNs to send to partners.
95
+ * `v0`: older/original format which is less compatible with other AS2 systems, but is the default for backwards-compatibility reasons.
96
+ * `v1`: improved format with better compatibility with other AS2 systems.
97
+ * `outbound_format`: Format to use when building outbound messages.
98
+ * `v0`: older/original format which is less compatible with other AS2 systems, but is the default for backwards-compatibility reasons.
99
+ * `v1`: improved format with better compatibility with other AS2 systems.
100
+ * `base64_scheme`: What type of base64 encoding to perform on outbound message bodies.
101
+ * `rfc4648`: older/original format which is less compatible with other AS2 systems, but is the default for backwards-compatibility reasons.
102
+ * `rfc2045`: format understood by more AS2 systems & recommended for new integrations.
103
+
104
+ ### Example
105
+
106
+ ```ruby
107
+ As2.configure do |conf|
108
+ conf.name = 'RUBYAS2'
109
+ conf.url = 'http://localhost:3000/as2'
110
+ conf.certificate = 'test/certificates/server.crt'
111
+ conf.pkey = 'test/certificates/server.key'
112
+ conf.domain = 'localhost'
113
+
114
+ conf.add_partner do |partner|
115
+ partner.name = 'MENDELSON'
116
+ partner.url = 'http://localhost:8080/as2/HttpReceiver'
117
+ partner.certificate = 'test/certificates/client.crt'
118
+ partner.outbound_format = 'v1'
119
+ partner.mdn_format = 'v1'
120
+ partner.base64_scheme = 'rfc2045'
121
+ end
122
+
123
+ conf.add_partner do |partner|
124
+ partner.name = 'OPENAS2'
125
+ partner.url = 'http://localhost:4088'
126
+ partner.certificate = 'test/certificates/client.crt'
127
+ partner.outbound_format = 'v1'
128
+ partner.mdn_format = 'v1'
129
+ partner.base64_scheme = 'rfc2045'
130
+ end
131
+ end
132
+ ```
133
+
51
134
  ## Usage
52
135
 
53
136
  Generate self signed server certificate:
data/examples/server.rb CHANGED
@@ -21,12 +21,18 @@ As2.configure do |conf|
21
21
  partner.name = 'MENDELSON'
22
22
  partner.url = 'http://localhost:8080/as2/HttpReceiver'
23
23
  partner.certificate = 'test/certificates/client.crt'
24
+ partner.outbound_format = 'v1'
25
+ partner.mdn_format = 'v1'
26
+ partner.base64_scheme = 'rfc2045'
24
27
  end
25
28
 
26
29
  conf.add_partner do |partner|
27
30
  partner.name = 'OPENAS2'
28
31
  partner.url = 'http://localhost:4088'
29
32
  partner.certificate = 'test/certificates/client.crt'
33
+ partner.outbound_format = 'v1'
34
+ partner.mdn_format = 'v1'
35
+ partner.base64_scheme = 'rfc2045'
30
36
  end
31
37
  end
32
38
 
data/lib/as2/client.rb CHANGED
@@ -172,7 +172,7 @@ module As2
172
172
  document_payload << "Content-Transfer-Encoding: base64\r\n"
173
173
  document_payload << "Content-Disposition: attachment; filename=#{file_name}\r\n"
174
174
  document_payload << "\r\n"
175
- document_payload << Base64.strict_encode64(document_content)
175
+ document_payload << base64_encode(document_content)
176
176
 
177
177
  signature = OpenSSL::PKCS7.sign(@server_info.certificate, @server_info.pkey, document_payload)
178
178
  signature.detached = true
@@ -201,7 +201,7 @@ module As2
201
201
  document_payload << "Content-Transfer-Encoding: base64\r\n"
202
202
  document_payload << "Content-Disposition: attachment; filename=#{file_name}\r\n"
203
203
  document_payload << "\r\n"
204
- document_payload << Base64.strict_encode64(document_content)
204
+ document_payload << base64_encode(document_content)
205
205
 
206
206
  signature = OpenSSL::PKCS7.sign(@server_info.certificate, @server_info.pkey, document_payload)
207
207
  signature.detached = true
@@ -211,7 +211,7 @@ module As2
211
211
  # strip off the '-----BEGIN PKCS7-----' / '-----END PKCS7-----' delimiters
212
212
  bare_pem_signature.gsub!(/^-----[^\n]+\n/, '')
213
213
  # and update to canonical \r\n line endings
214
- bare_pem_signature.gsub!(/(?<!\r)\n/, "\r\n")
214
+ bare_pem_signature = As2.canonicalize_line_endings(bare_pem_signature)
215
215
 
216
216
  # this is a hack until i can determine a better way to get the micalg parameter
217
217
  # from the pkcs7 signature generated above...
@@ -315,6 +315,11 @@ module As2
315
315
 
316
316
  private
317
317
 
318
+ def base64_encode(content)
319
+ encoded = As2.base64_encode(content, scheme: @partner.base64_scheme)
320
+ As2.canonicalize_line_endings(encoded)
321
+ end
322
+
318
323
  # extract the MDN body from a multipart/signed wrapper & attempt to verify
319
324
  # the signature
320
325
  #
data/lib/as2/config.rb CHANGED
@@ -12,10 +12,20 @@ module As2
12
12
  end
13
13
  end
14
14
 
15
- class Partner < Struct.new :name, :url, :encryption_certificate, :encryption_cipher, :signing_certificate, :tls_verify_mode, :mdn_format, :outbound_format
15
+ class Partner < Struct.new :name, :url, :encryption_certificate, :encryption_cipher, :signing_certificate, :tls_verify_mode, :mdn_format, :outbound_format, :base64_scheme
16
16
  def initialize
17
17
  # set default.
18
18
  self.encryption_cipher = 'aes-256-cbc'
19
+ self.base64_scheme = 'rfc4648'
20
+ end
21
+
22
+ def base64_scheme=(scheme)
23
+ scheme_s = scheme.to_s
24
+ valid_schemes = As2.valid_base64_schemes
25
+ if !valid_schemes.include?(scheme_s)
26
+ raise ArgumentError, "base64_scheme '#{scheme_s}' must be one of #{valid_schemes.inspect}"
27
+ end
28
+ self['base64_scheme'] = scheme_s
19
29
  end
20
30
 
21
31
  def url=(url)
data/lib/as2/server.rb CHANGED
@@ -165,7 +165,7 @@ module As2
165
165
  # strip off the '-----BEGIN PKCS7-----' / '-----END PKCS7-----' delimiters
166
166
  bare_pem_signature.gsub!(/^-----[^\n]+\n/, '')
167
167
  # and update to canonical \r\n line endings
168
- bare_pem_signature.gsub!(/(?<!\r)\n/, "\r\n")
168
+ bare_pem_signature = As2.canonicalize_line_endings(bare_pem_signature)
169
169
 
170
170
  # this is a hack until i can determine a better way to get the micalg parameter
171
171
  # from the pkcs7 signature generated above...
data/lib/as2/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module As2
2
- VERSION = "0.11.0"
2
+ VERSION = "0.12.0"
3
3
  end
data/lib/as2.rb CHANGED
@@ -23,6 +23,54 @@ module As2
23
23
  "<#{server_info.name}-#{Time.now.strftime('%Y%m%d-%H%M%S')}-#{SecureRandom.uuid}@#{server_info.domain}>"
24
24
  end
25
25
 
26
+ def self.valid_base64_schemes
27
+ [
28
+ 'rfc2045',
29
+ 'rfc4648'
30
+ ]
31
+ end
32
+
33
+ # create a base64 string from content, based on the given encoding scheme
34
+ #
35
+ # @param [String] content
36
+ # @param [String] scheme one of As2.valid_base64_schemes
37
+ # @return [String]
38
+ def self.base64_encode(content, scheme: 'rfc4648')
39
+ case scheme.to_s
40
+ when 'rfc2045'
41
+ # "This method complies with RFC 2045."
42
+ # https://ruby-doc.org/stdlib-3.0.4/libdoc/base64/rdoc/Base64.html#method-i-encode64
43
+ # https://www.rfc-editor.org/rfc/rfc2045#section-6.8
44
+ then Base64.encode64(content)
45
+ when 'rfc4648'
46
+ # "This method complies with RFC 4648."
47
+ # https://ruby-doc.org/stdlib-3.0.4/libdoc/base64/rdoc/Base64.html#method-i-strict_encode64
48
+ # https://www.rfc-editor.org/rfc/rfc4648#section-4
49
+ then Base64.strict_encode64(content)
50
+ else
51
+ raise ArgumentError, "unsupported scheme '#{scheme}'. choose one of: #{valid_base64_schemes}"
52
+ end
53
+ end
54
+
55
+ # canonicalize all line endings in the given text.
56
+ #
57
+ # "\n" becomes "\r\n"
58
+ # "\r\n" remains "\r\n"
59
+ #
60
+ # Conversion to canonical form:
61
+ # The entire body ... is converted to a universal canonical
62
+ # form. ... For example, in the case of text/plain data, the text
63
+ # must be converted to a supported character set and lines must
64
+ # be delimited with CRLF delimiters in accordance with RFC 822.
65
+ #
66
+ # https://www.rfc-editor.org/rfc/rfc2049#page-9
67
+ #
68
+ # @param [String] content
69
+ # @return [String] content, but with all bare \n replaced by \r\n
70
+ def self.canonicalize_line_endings(content)
71
+ content.gsub(/(?<!\r)\n/, "\r\n")
72
+ end
73
+
26
74
  # Select which algorithm to use for calculating a MIC, based on preferences
27
75
  # stated by sender & our list of available algorithms.
28
76
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: as2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OfficeLuv
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-09-14 00:00:00.000000000 Z
12
+ date: 2024-02-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mail
@@ -205,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
205
  - !ruby/object:Gem::Version
206
206
  version: '0'
207
207
  requirements: []
208
- rubygems_version: 3.1.4
208
+ rubygems_version: 3.4.10
209
209
  signing_key:
210
210
  specification_version: 4
211
211
  summary: Simple AS2 server and client implementation