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?

1
  • Use MIME boundaries?
    – Rob
    Mar 1, 2012 at 15:37

2 Answers 2

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
5
  • thanks for the comprehensive response, given my input file is minimum.json', encrypted minimum.json.crypt`, what is the correct openssl command to create one single text body, ready to be used as a HTTP post/put body? Mar 1, 2012 at 15:59
  • 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 Mar 1, 2012 at 16:10
  • 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----- Mar 1, 2012 at 16:15
  • 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 Mar 1, 2012 at 16:42
  • 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. Mar 2, 2012 at 16:09
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']

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .