Formatting OpenSSL encrypted message, and signature in the same plaintext file

0

I'm working on designing an API which requires encrypted messages to be signed and sent over TLS. The TLS is HTTP/SSL.

The messages themselves are a few hundred Kb (at most) of JSON data, encrypted with asymmetrical keys. The PK infrastructure is solved by a network of trust, and the parties being in the same city, thus we can exchange keys in person.

We are unable to rely on GnuPG/PGP, as the library support in the languages we are using is unknown, and we would prefer to directly use OpenSSL.

We want to send, in one plaintext chunk the following, the message, and it's signature. With GnuPG/PGP this might look like:


-----BEGIN PGP SIGNED MESSAGE-----
#
# Encrypted message data here...
#
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (MingW32)

iQIVAwUBPOCy1mM8BmRItYg4AQKWrA//fR5LKFyt+78CMtfpzkHgCVFyEe2ImsBy
FJ2HvzRIP4Bvor1iEOZ9A0fux8gBNXrvEtaDXSiGyXH+Ru4F3g1+K119fgBPRBgo
oOTbSLZSlRYWp8mRALsiWXKEHWgpy4zIHVTY6tPJdxFBZYJXnQj/4S6MRP+eJdam
rU8ufExxaqQPw+KCNEVCSk1yHZ886k6MTSa1oDqUOLiM1cBDCtD8Jv+BE0gLHPb9
1h7lEka8QGNe+P7iiUzvsuD7HCL6dGb6T70/KBBHIP6lDwOgUX3eTd8e+I3jczs9
RyEmd6G4swM3IzCD1km+SN5/k5QsMjd6Lw5fB95Mroi47QNpya8ifYbMgCg0+BVm
c7QOwr79+9cJiKhEICbMf5pKQWzP/AznaYlM0IOGGCvxa5loLl7BbtvktVMocitF
zWM9SB0kmSu3OlMxjXYcBsyHCHN4dTpCD9d1jfbgth9YV06sWpONLohdaWx+n9kO
CxsSDGI+aW8sGKHWonw0Uy4UAvUzY3tiZTzTF+FzoJzhy13KK1j4Y0MMx1jZ68f9
R9wSKVdiyXwuMXkWWK0uxSZuBz4mTofZ7YmFm7UdxOH4bMnO+rWNCSPR7md+X0j1
nQSwtxEnIu7Tucb/ZG3t9kR+KTByPTu7tHINr4HFd8m2Cu7Wi10TP/EBtXbtYA/1
SBaUXcbgCD8=
=Hn6O
-----END PGP SIGNATURE-----

However I wasn't able to find a suitable way of doing the same with OpenSSL. smime as I understand it is not suitable, as we're not sending mails.

The two chunks in question are:


$ openssl enc -base64 < minimum.json.crypt
sxuEWSFRXxVOylBA/Z38slAQeY9hzypEt9ZmGDSORBID0VMyvbj1bF5jnfA/rpKm
2HsKh8mZq+Gcgf9iPvVoOpzIgAdVqI3CK6CjXCi87y9LL0alYXXFs/ZEQp46URDv
cv8tiOjEnx+u/c1RpyKHHq0QBKStN8jrdQfVCWfoGhw8bS4SfyXxX/OcngKBp094
lcoR9DTz4F/pkvLwrr0wwCMv2/ayqI5Q6ZzB5Y9OUrb4smLNK/Q7PWsO4sYcGoPL
WpmjZ1TNPCvepWQhqEGrVAHxxCdjNczqaRgia5wqZnlLfhCRRHQqADN0nApabAvS
kXerrgcY25Qy4bWjCk/Y0Q==

$  openssl enc -base64 -in minimum.json.sig 
onVyfVDakk6DP28T40bt2C2xF+gEZwssemNQIg+pz/PjgTQRTDN42K9p81aSkbkN
Wdlab/TqJCmGNZuIhGKe6f+oDTL6PNofEDr8QGyLzv5Lk+2+/fcD/OV2bI6RV2Ar
95on3jzwKIsaDyMT/9oHtBf7EiZptNLpGp8Fkp+4tfgt7z5w1Di4sA1sCUVdgmsR
KIEa2MaOQxKG9DyrxOz/Fjz7RUPMRjCF+AJ8EFkGfzQmj+PmOxwnRW4nMVVqf858
59NXWy1W5L5Smf1/XC14eLh6LMcmJpHeiEIVu9RMKAVJagMP8eOVxM4QAt1Jvq9W
6Dqmako0I+0Rjt9FxFTRAQ==

The signature is generated from a SHA1 of the original un-encrypted message body.

Our intention is to send the whole formatted document as an HTTP POST body. Which is the correct format, is there a standard?

Lee Hambley

Posted 2012-03-01T15:14:51.800

Reputation: 301

Use MIME boundaries? – Rob – 2012-03-01T15:37:49.287

Answers

1

S/MIME is a standard for securing MIME data, not email specifically. There shouldn't be any problems with using it with HTTP, as both use the same MIME formats and even similar header syntax. For example:

POST /receiver HTTP/1.1
Host: example.com
Content-Type: multipart/signed; protocol="application/pkcs7-signature";
    micalg=sha1; boundary="------------ms040900030501050600040105"
Content-Length: 476

--------------ms040900030501050600040105
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

This is a sample message.

--------------ms040900030501050600040105
Content-Type: application/pkcs7-signature
Content-Transfer-Encoding: base64

MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIEKDCC
BCQwggMMoAMCAQICAiAJMA0GCSqGSIb3DQEBBQUAMDgxCzAJBgNVBAYTAkxUMRIwEAYDVQQK
(trimmed)
--------------ms040900030501050600040105--

(Note that OpenPGP has an equivalent as well; PGP/MIME, which is implemented by the majority of PGP-capable email clients, and again can be used by HTTP.)


S/MIME uses PKCS#7 as the base. You could alternatively use raw PKCS#7 could be used without any S/MIME wrapping, perhaps using openssl smime -pk7out, which takes a S/MIME message and outputs a PKCS#7 signedData structure.

openssl smime -sign | openssl smime -pk7out | openssl asn1parse -i

user1686

Posted 2012-03-01T15:14:51.800

Reputation: 283 655

thanks for the comprehensive response, given my input file is minimum.json', encryptedminimum.json.crypt`, what is the correct openssl command to create one single text body, ready to be used as a HTTP post/put body? – Lee Hambley – 2012-03-01T15:59:37.700

I always get: openssl smime -sign -signer documentation-private.pem -in minimum.json.crypt upstream-public.pem which throws unable to load certificate 17256:error:0906D06C:PEM routines:PEM_read_bio:no start line:/SourceCache/OpenSSL098/OpenSSL098-44/src/crypto/pem/pem_lib.c:648:Expecting: TRUSTED CERTIFICATE – Lee Hambley – 2012-03-01T16:10:00.307

I believe the keys are of the correct type: head -n1 upstream-public.pem shows -----BEGIN PUBLIC KEY-----, and head -n1 documentation-private.pem shows -----BEGIN RSA PRIVATE KEY----- – Lee Hambley – 2012-03-01T16:15:05.433

I'm assuming the problem is that my test certificates in this instance weren't even self-signed, they were unsigned, generated with : $ openssl genrsa -des3 -out documentation-private.pem 2048, $ openssl rsa -in documentation-private.pem -out documentation-public.pem -outform PEM -pubout – Lee Hambley – 2012-03-01T16:42:41.263

I was able to do this using the Ruby RESTClient library to format the MIME Digest type request body, with the signature and message body as two separate text/plain parts. – Lee Hambley – 2012-03-02T16:09:31.670

0

I've done something similar recently in JavaScript for Ajax posts, just using mimi boundaries separating the post content Mime boundaries will work what ever technology.

//SIMPLE JS EXAMPLE:

var body = '';
var boundary=Math.random().toString().substr(2);
body += "--"+boundary+"\r\ncontent-disposition: form-data; name=content1;\r\ncontent-type: text/plain\r\n\r\n"+content1+"\r\n";
body += "--"+boundary+"\r\ncontent-disposition: form-data; name=content2;\r\ncontent-type: text/plain\r\n\r\n"+content2+"\r\n";
body += "--"+boundary+"--\r\n";

$.ajax({
  url:"/api",
  type: 'POST',
  context:this,
  contentType: 'multipart/form-data; charset=utf-8; boundary=' + boundary,
  data: body,
  error: error_callback,
  success: success_callback
});

values are just received in server app with regular params

//rack
params[:content1]
params[:content2]

//php
$_POST['content1']
$_POST['content2']

Rob

Posted 2012-03-01T15:14:51.800

Reputation: 649