S/MIME
Chapter Seventy
Syllabus topic Module 2, "Electronic Mail Security: S/MIME"
Pages 460 to 467 of 678
In one line
S/MIME is PGP's job done the X.509 way: it signs and encrypts email using certificates issued by certification authorities, and it is built into the mail programs most organisations already use.
In the words an answer should use, which are RFC 8551's: S/MIME (Secure/Multipurpose Internet Mail Extensions) "provides a consistent way to send and receive secure MIME data. Digital signatures provide authentication, message integrity, and non-repudiation with proof of origin. Encryption provides data confidentiality. Compression can be used to reduce data size." The current version is 4.0, specified in RFC 8551 (April 2019).
MIME first
S/MIME is a security layer on top of MIME, and cannot be understood without it.
The problem MIME solved. Internet mail was defined in 1982 by RFC 822, for text. RFC 2045, which defines MIME, lists what that left out: non-text messages "are simply not mentioned"; text in character sets richer than US-ASCII, meaning most of the world's languages, had no mechanism; and mail systems limited messages to "relatively short lines (e.g. 1000 characters or less) of 7bit US-ASCII". A photograph, a spreadsheet, or a sentence with a rupee sign in it could not be sent as it was.
MIME's five header fields, from RFC 2045:
| Header field | What it says |
|---|---|
MIME-Version | that the message follows MIME; its value is 1.0 |
Content-Type | what the content is, as a type and subtype, with parameters: text/plain; charset="utf-8" |
Content-Transfer-Encoding | how the content was converted to survive mail transport |
Content-ID | an identifier, so that one part can refer to another |
Content-Description | a plain-language description of the part |
The seven top-level content types, from RFC 2046. Five are discrete, holding one kind of data, and two are composite, holding other parts:
| Type | Common subtypes | Holds |
|---|---|---|
text | plain, enriched | readable text in a stated character set |
image | jpeg, gif | a picture |
audio | basic | sound |
video | mpeg | moving pictures |
application | octet-stream, pdf | data for a program, or raw bytes |
multipart | mixed, alternative, parallel, digest | several parts, each with its own headers |
message | rfc822, partial, external-body | an encapsulated message, or a fragment of one |
The transfer encodings, which say how bytes were made safe for mail:
| Encoding | Meaning | Used for |
|---|---|---|
7bit | short lines of US-ASCII, unchanged | plain English text |
8bit | short lines that may contain 8-bit characters | text, where the mail path allows it |
binary | any bytes, any line length | only where the path allows it |
quoted-printable | printable ASCII left as it is; every other byte written as = and two hexadecimal digits | text that is mostly ASCII |
base64 | three bytes to four printable characters, exactly radix-64 | binary data |
Canonical form. Different computers end lines differently. Before a MIME entity is signed, it is put into a canonical form in which, for text, every line ends with a carriage return and a line feed. Both the signer and the verifier hash that form, so that a message is not rejected merely because a mail system changed its line endings. The run below shows what happens if that step is skipped.
S/MIME
What S/MIME adds
S/MIME wraps MIME entities in the Cryptographic Message Syntax (CMS) of RFC 5652, the structure the run takes apart, and marks the result with its own MIME types.
The forms of an S/MIME message, from RFC 8551 s.3:
| Form | What it is | Who can read the content |
|---|---|---|
| Enveloped data | the content encrypted with a one-time content-encryption key, and that key encrypted for each recipient | only the recipients |
| Signed data | the content and its signature packed together in one CMS object, then base64-encoded | only an S/MIME-capable reader |
| Clear-signed data | the content left readable as the first part of a multipart/signed message, the signature attached as a second part | anyone; only S/MIME readers can check the signature |
| Signed and enveloped | one form applied inside the other: signed then encrypted, or encrypted then signed | only the recipients |
| Compressed data | the content compressed, usually before the other operations | an S/MIME-capable reader |
Clear-signing is why a signed business email opens normally in any mail program. The run below takes apart exactly such a message.
The MIME types. An S/MIME object travels as application/pkcs7-mime, with an smime-type parameter telling the mail program what is inside without opening it: enveloped-data, signed-data, certs-only, compressed-data or authEnveloped-data. A clear-signed message is multipart/signed with the protocol application/pkcs7-signature, and its signature part is named smime.p7s.
How a signed message is made, following RFC 8551:
- Prepare the MIME entity to be signed, and convert it to canonical form.
- Compute its digest, SHA-256.
- Build the signed attributes: the content type, the signing time, the digest just computed, and the sender's cryptographic capabilities.
- Sign the signed attributes with the sender's private key.
- Pack the digest algorithm, the sender's certificate and the signature into a CMS
SignedDataobject, and attach it.
Note step 4: what is signed is not the message itself but the attributes, one of which is the message's digest. That lets the signing time and the capabilities be protected by the same signature.
Algorithms, RFC 8551
RFC 8551 uses two extra labels. MUST- means required now but expected to be downgraded; SHOULD+ means recommended now and expected to become required.
| Purpose | Required | Being phased in or out |
|---|---|---|
| Message digest | SHA-256 and SHA-512 | |
| Signatures, receiving | ECDSA on P-256 with SHA-256; EdDSA on curve25519 | RSA PKCS #1 v1.5 with SHA-256 is MUST-; RSA-PSS with SHA-256 SHOULD |
| Signatures, sending | at least one of ECDSA P-256 or EdDSA | RSA PKCS #1 v1.5 MUST- |
| Protecting the content key | ECDH on P-256; ECDH on X25519 | RSA encryption MUST-; RSA-OAEP SHOULD+ |
| Content encryption | AES-128 GCM and AES-256 GCM | AES-128 CBC MUST-; ChaCha20-Poly1305 SHOULD+ |
S/MIME
The direction of travel is the same as in RFC 9580 for OpenPGP: away from RSA and towards elliptic curves, and towards authenticated encryption modes such as GCM.
Certificates in S/MIME
S/MIME uses X.509 version 3 certificates, exactly those of the X.509 chapters, validated by the same path rules. The user's email address appears in the certificate, in the subject alternative name as an rfc822Name, so that the mail program can check that the certificate belongs to the address the message came from.
The mail program, the user agent, has three jobs with certificates: generate or obtain the user's own key pair and certificate, from a CA; store and look up the certificates of correspondents, which can be taken from the signed messages they send, since a signed S/MIME message can carry the signer's certificate, as the one below does; and validate every certificate it relies on, including its path and its revocation status. An organisation's staff certificates come from a CA that it runs itself or that it buys certificates from.
The enhanced security services
RFC 2634 (June 1999) defines further services on top of S/MIME, built on triple wrapping: a message signed, then encrypted, then signed again.
- Signed receipts. The sender asks for a receipt; the recipient's software returns a signed receipt covering the original message's signature, proving the message arrived and was checked.
- Security labels. A signed attribute classifying the content, such as "confidential", which receiving systems can use for access control.
- Secure mailing lists. A mail list agent receives one encrypted message and re-encrypts it for each member, so the sender need not know the list's membership.
- Signing certificate. A signed attribute naming exactly which certificate was used to sign, so that one certificate cannot be substituted for another.
The run: a real signed message, taken apart
The message below was produced with OpenSSL 3.6.1, signing a short notice with a throwaway certificate made for the fictional address asha@college.example. It is exactly what a mail program would send, shown with plain line endings.
MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha-256"; boundary="----14EF7E8710C9940FB86E19CC54042408"
This is an S/MIME signed message
------14EF7E8710C9940FB86E19CC54042408
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
The examination fee for Semester V is =E2=82=B9 1,500, payable by 15 Octob=
er.
Asha Kulkarni, Examination Section
------14EF7E8710C9940FB86E19CC54042408
Content-Type: application/pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
MIIGTAYJKoZIhvcNAQcCoIIGPTCCBjkCAQExDTALBglghkgBZQMEAgEwCwYJKoZI
hvcNAQcBoIIDqzCCA6cwggKPoAMCAQICFGfKD1Yn+tJ141rJ+cRvUaeb8JVwMA0G
CSqGSIb3DQEBCwUAMD8xCzAJBgNVBAYTAklOMRgwFgYDVQQKDA9FeGFtcGxlIENv
bGxlZ2UxFjAUBgNVBAMMDUFzaGEgS3Vsa2FybmkwHhcNMjYwOTMwMTAxOTMwWhcN
MzYwOTI3MTAxOTMwWjA/MQswCQYDVQQGEwJJTjEYMBYGA1UECgwPRXhhbXBsZSBD
b2xsZWdlMRYwFAYDVQQDDA1Bc2hhIEt1bGthcm5pMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA5mV5Zuz+iPv/f1zKBE2CUAO8gED4Ax5keAqI2fMyB9dc
RfzfhT68B+K6OvwRqlxQeE6IyksOApBSVD1nrhH5iGqjg5H0aHlWgnjKwNjrumLf
jcZ/NyTEfwL0p1KfDzH5cK/USWCSKF5CIlKpwbp5duMPfkGTFJt776iRN1XfwGwp
sXDuJ/WwBnLv7epR1WHQMMVno2hbtl3TNDNOgSnVxiNIa14O+ik9mtEEFTVXbmGj
3v9lVWm91/w43O9p1GvzYmP3dHpWhpxm0ade0kG3aWGt8F8Wh4CQFl42iA2Rm4h0
tK9yTgW4A5WzPgDd1OHpPo/07StEYxQSEh31SRZrVQIDAQABo4GaMIGXMB0GA1Ud
DgQWBBTmruPRK4v0ukC+BQgCKdLC3t+IFjAfBgNVHSMEGDAWgBTmruPRK4v0ukC+
BQgCKdLC3t+IFjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdEQQYMBaBFGFzaGFAY29s
bGVnZS5leGFtcGxlMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcD
BDANBgkqhkiG9w0BAQsFAAOCAQEAZOBriMXb3OJ8U4l1UlTyfseb2TVxvhHb64yo
hH0bVmrpuS6WuBmnS6rIPVrnRhHbNn8lGiRR17SyuTbCta9XhiQLc5TNwQ2PS8iC
dqFYH85hHW9qw/ZVecXGFDJu3xbmzmMDl0iV1j7RcHxX2U8CXQeegqjbfQD5Gp72
OqIkbNx7QkjygaH/tBUcCXyHRvPtZrmmAtAZW3bfQN1fVX63Htkx3uDsu1WQl5M9
5W+D8N/9Cf/lEbfmek4CnVk5jPD3S8x/i/2e7k5Zgh3+cYHHptst+pnduUcHsz7h
oMfwPWd+od5ongMOUAY5q21RrVElZVuAfBXCKo+jI68LyIU/YjGCAmcwggJjAgEB
MFcwPzELMAkGA1UEBhMCSU4xGDAWBgNVBAoMD0V4YW1wbGUgQ29sbGVnZTEWMBQG
A1UEAwwNQXNoYSBLdWxrYXJuaQIUZ8oPVif60nXjWsn5xG9Rp5vwlXAwCwYJYIZI
AWUDBAIBoIHkMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkF
MQ8XDTI2MDkzMDEwMTkzMFowLwYJKoZIhvcNAQkEMSIEIPZgHkv4i0xH6s63sQ5o
4ADFyZZyCS2hmbpT73ELtdOCMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZIAWUDBAEq
MAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcN
AwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0G
CSqGSIb3DQEBAQUABIIBAMPGYtvfDqHzA8g0sRqk1v2pSpHwcT/Z0g6E0O0TuBQn
CRRPhd1ePnLGcvei9k16fEkTv+RLdQtlpVY/TIu6lxVPD71E1r9PqAmiwkMXek/h
s6V5Gkn54tBoJIRlFHfzaTru7/xH3dumTWhLvlodmo2gBWGsh6mhKATNrs8jAryA
s57SFQHozS27xfTVr5ROKz/TnselobtsXV8hYk5zPiJezc6I/YXk3GxcnUI0zby3
zyjrzWQ+TEir0LAz6lOd+e/oRHq/OrCo8zXV1GItTir74lYFYgFIzlh2rNTmpzxF
8OMKaYXICTggjfsGSjMFBIjIAfQukysSuex1mk1+Oi0=
------14EF7E8710C9940FB86E19CC54042408--S/MIME
The listing reads the MIME structure, decodes the quoted-printable text, takes the CMS signature apart with the same DER reader as the X.509 chapters, and verifies the signature from integers alone.
# A real S/MIME signed message, taken apart and verified: MIME, then CMS, then RSA.
import base64, datetime, hashlib, quopri
raw = open('signed-message.eml').read()
header, rest = raw.split('\n\n', 1)
print('THE OUTER MIME HEADERS')
for line in header.split('\n'):
name, value = line.split(': ', 1)
params = value.split('; ')
print(' %s: %s' % (name, params[0]))
for p in params[1:]:
print(' ; %s' % p)
boundary = header.split('boundary="')[1].split('"')[0]
parts = rest.split('--' + boundary)
signed_part, signature_part = parts[1][1:-1], parts[2]
part_head, part_body = signed_part.split('\n\n', 1)
print()
print('PART 1, THE SIGNED CONTENT')
for line in part_head.split('\n'):
print(' ', line)
print(' quoted-printable, as sent :', part_body.split('\n')[0])
print(' decoded :',
quopri.decodestring(part_body.encode()).decode().split('\n')[0])
# ---- a DER reader, as in the X.509 chapters ----------------------------------------------
def tlv(d, i):
tag, n, j = d[i], d[i + 1], i + 2
if n & 0x80:
k = n & 0x7F
n, j = int.from_bytes(d[j:j + k], 'big'), j + k
return tag, j, j + n
def items(d, s, e):
out = []
while s < e:
t, a, b = tlv(d, s)
out.append((t, a, b, s)); s = b
return out
def oid(b):
arcs, v = [b[0] // 40, b[0] % 40], 0
for x in b[1:]:
v = (v << 7) | (x & 0x7F)
if not x & 0x80: arcs.append(v); v = 0
return '.'.join(map(str, arcs))
NAMES = {'1.2.840.113549.1.7.2': 'signedData', '1.2.840.113549.1.7.1': 'data',
'1.2.840.113549.1.9.3': 'contentType', '1.2.840.113549.1.9.5': 'signingTime',
'1.2.840.113549.1.9.4': 'messageDigest', '1.2.840.113549.1.9.15': 'smimeCapabilities',
'2.16.840.1.101.3.4.2.1': 'SHA-256', '2.16.840.1.101.3.4.1.42': 'AES-256-CBC',
'2.16.840.1.101.3.4.1.22': 'AES-192-CBC', '2.16.840.1.101.3.4.1.2': 'AES-128-CBC',
'1.2.840.113549.3.7': 'Triple-DES-CBC', '1.2.840.113549.3.2': 'RC2-CBC',
'1.3.14.3.2.7': 'DES-CBC', '1.2.840.113549.1.1.1': 'rsaEncryption'}
der = base64.b64decode(signature_part.split('\n\n', 1)[1])
_, s, e = tlv(der, 0)
content_type, wrapper = items(der, s, e)
signed_data = items(der, *tlv(der, wrapper[1])[1:])
certificates = next(x for x in signed_data if x[0] == 0xA0)
signer = items(der, signed_data[-1][1], signed_data[-1][2])[0]
fields = items(der, signer[1], signer[2])
signed_attrs = next(x for x in fields if x[0] == 0xA0)
signature = next(x for x in reversed(fields) if x[0] == 0x04)
print()
print('PART 2, THE SIGNATURE: %d bytes of CMS (RFC 5652)' % len(der))
print(' content type ', NAMES[oid(der[content_type[1]:content_type[2]])])
attrs = {}
for _, a, b, _ in items(der, signed_attrs[1], signed_attrs[2]):
p = items(der, a, b)
attrs[NAMES[oid(der[p[0][1]:p[0][2]])]] = items(der, p[1][1], p[1][2])[0]
t = attrs['signingTime']
print(' signed attribute signingTime ',
datetime.datetime.strptime(der[t[1]:t[2]].decode(), '%y%m%d%H%M%SZ'), 'UTC')
digest = der[attrs['messageDigest'][1]:attrs['messageDigest'][2]]
print(' signed attribute messageDigest ', digest.hex()[:32] + '...')
caps = attrs['smimeCapabilities']
offered = []
for cap in items(der, caps[1], caps[2]):
alg = items(der, cap[1], cap[2])
label = NAMES.get(oid(der[alg[0][1]:alg[0][2]]), oid(der[alg[0][1]:alg[0][2]]))
if len(alg) > 1 and alg[1][0] == 0x02: # RC2 carries its key size
label += ' %d-bit' % int.from_bytes(der[alg[1][1]:alg[1][2]], 'big')
offered.append(label)
print(' signed attribute smimeCapabilities, in the sender\'s order of preference:')
for i in range(0, len(offered), 4):
print(' ' + ', '.join(offered[i:i + 4]))
cert = items(der, certificates[1], certificates[2])[0]
c = der[cert[3]:cert[2]]
tbs = items(c, *tlv(c, 0)[1:])[0]
f = items(c, tbs[1], tbs[2])
cn = [c[p[1][1]:p[1][2]].decode() for _, s1, e1, _ in items(c, f[5][1], f[5][2])
for _, s2, e2, _ in items(c, s1, e1) for p in [items(c, s2, e2)]
if oid(c[p[0][1]:p[0][2]]) == '2.5.4.3'][0]
spki = items(c, f[6][1], f[6][2])
key = c[spki[1][1] + 1:spki[1][2]]
(_, a, b, _), (_, x, y, _) = items(key, *tlv(key, 0)[1:])
n, e = int.from_bytes(key[a:b], 'big'), int.from_bytes(key[x:y], 'big')
print(' certificate carried inside ', cn, '| RSA-%d' % n.bit_length())
# ---- verification, RFC 8551 s.3.1.1 and RFC 5652 s.5.4 -----------------------------------
def rsa_ok(message, sig):
size = (n.bit_length() + 7) // 8
tail = bytes.fromhex('3031300d060960864801650304020105000420') + \
hashlib.sha256(message).digest()
return pow(sig, e, n).to_bytes(size, 'big') == \
b'\x00\x01' + b'\xff' * (size - 3 - len(tail)) + b'\x00' + tail
canonical = signed_part.replace('\n', '\r\n').encode() # every line ends CR LF
attrs_as_set = b'\x31' + der[signed_attrs[3] + 1:signed_attrs[2]]
sig = int.from_bytes(der[signature[1]:signature[2]], 'big')
print()
print('VERIFYING')
print(' SHA-256 of the part in canonical form equals messageDigest:',
hashlib.sha256(canonical).digest() == digest)
print(' the same part hashed WITHOUT converting line endings :',
hashlib.sha256(signed_part.encode()).digest() == digest)
print(' RSA signature over the signed attributes verifies :', rsa_ok(attrs_as_set, sig))
altered = canonical.replace(b'1,500', b'15,000')
assert altered != canonical
print(' the fee changed from 1,500 to 15,000, digest still matches:',
hashlib.sha256(altered).digest() == digest)
print()
print('THE COST OF MAKING IT MAIL-SAFE')
print(' signature: %d bytes of DER became %d characters of base64'
% (len(der), len(signature_part.split('\n\n', 1)[1].replace('\n', ''))))
print(' whole message: %d characters, to carry %d characters of text'
% (len(raw), len(quopri.decodestring(part_body.encode()).decode())))S/MIME
THE OUTER MIME HEADERS
MIME-Version: 1.0
Content-Type: multipart/signed
; protocol="application/pkcs7-signature"
; micalg="sha-256"
; boundary="----14EF7E8710C9940FB86E19CC54042408"
PART 1, THE SIGNED CONTENT
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
quoted-printable, as sent : The examination fee for Semester V is =E2=82=B9 1,500, payable by 15 Octob=
decoded : The examination fee for Semester V is ₹ 1,500, payable by 15 October.
PART 2, THE SIGNATURE: 1616 bytes of CMS (RFC 5652)
content type signedData
signed attribute signingTime 2026-09-30 10:19:30 UTC
signed attribute messageDigest f6601e4bf88b4c47eaceb7b10e68e000...
signed attribute smimeCapabilities, in the sender's order of preference:
AES-256-CBC, AES-192-CBC, AES-128-CBC, Triple-DES-CBC
RC2-CBC 128-bit, RC2-CBC 64-bit, DES-CBC, RC2-CBC 40-bit
certificate carried inside Asha Kulkarni | RSA-2048
VERIFYING
SHA-256 of the part in canonical form equals messageDigest: True
the same part hashed WITHOUT converting line endings : False
RSA signature over the signed attributes verifies : True
the fee changed from 1,500 to 15,000, digest still matches: False
THE COST OF MAKING IT MAIL-SAFE
signature: 1616 bytes of DER became 2156 characters of base64
whole message: 2854 characters, to carry 106 characters of textS/MIME
What the run establishes, in order.
The outer headers say everything a mail program needs. multipart/signed, the signature's type application/pkcs7-signature, the digest algorithm sha-256, and the boundary string that separates the parts.
Part 1 is readable by anyone. Its text is quoted-printable: the rupee sign is written =E2=82=B9, its three UTF-8 bytes, and a line that would be too long ends in =, a soft line break. Decoded, it is the notice as the sender wrote it.
Part 2 is a CMS SignedData object, 1,616 bytes, carrying signed attributes (the signing time, 30 September 2026 at 10:19:30 UTC; the message digest; and the sender's capabilities, in order of preference) and the signer's own certificate.
The signature verifies, but only in canonical form. The SHA-256 of part 1, with every line ended by a carriage return and line feed, equals the signed message-digest attribute. Hashed as it is displayed, with plain line endings, it does not. That is why canonicalisation is a required step, not a detail. The RSA signature over the signed attributes then verifies with the certificate's public key.
Any change is detected. Change the fee from 1,500 to 15,000 and the digest no longer matches, so the signature fails.
Mail-safety has a price. The 1,616-byte signature travels as 2,156 base64 characters, and a message carrying 106 characters of text is 2,854 characters long.
One observation to carry away. The capabilities OpenSSL 3.6.1 advertises by default still include Triple DES, RC2 with 40-bit keys and single DES, none of which RFC 8551 lists. Those capabilities are only offers, listed in order of preference, and here the list begins with AES-256. But software keeps old algorithms on offer long after the standards drop them.
S/MIME against PGP
This is the comparison a question spanning the email chapters asks for.
| PGP (OpenPGP) | S/MIME | |
|---|---|---|
| Standard | RFC 9580 (2024) | RFC 8551 (2019), with CMS, RFC 5652 |
| Who vouches for a key | users, through the web of trust; or direct fingerprint checks | certification authorities, through X.509 |
| Certificate format | OpenPGP keys with signatures on them | X.509 version 3 |
| Message structure | OpenPGP packets | MIME entities wrapped in CMS |
| Encoding for mail | radix-64 armor | MIME, with base64 |
| Clear-signing | cleartext signature framework | multipart/signed |
| Required signature algorithm today | Ed25519 | ECDSA P-256 or EdDSA; RSA PKCS #1 v1.5 still MUST- |
| Required content encryption | AES-128 in OCB mode | AES-128 GCM and AES-256 GCM |
The sentence that decides it: PGP and S/MIME protect email with the same cryptography, a hash signed with the sender's private key and a one-time content key encrypted for the recipient; they differ in how trust in public keys is established, the web of trust against certification authorities, and in the message formats that follow from that.
S/MIME
What beginners get wrong here
Saying S/MIME encrypts the message with the recipient's public key. As in PGP, the message is encrypted with a one-time content key, and only that key is encrypted for each recipient.
Forgetting canonicalisation. A signature over text is computed on the canonical form, with every line ending in a carriage return and a line feed; hash anything else and verification fails, as the run shows.
Confusing signed data with clear-signed data. Signed data packs content and signature together and needs S/MIME to read; clear-signed data leaves the content readable by anyone.
Thinking the message is signed directly. The signature covers the signed attributes, which include the message's digest.
Mixing up MIME and S/MIME. MIME is the format for carrying any content in mail; S/MIME adds signing and encryption to MIME entities.
Quick revision
- MIME (RFC 2045, 2046): five headers, MIME-Version, Content-Type, Content-Transfer-Encoding, Content-ID, Content-Description; seven types, text, image, audio, video, application, multipart, message; encodings 7bit, 8bit, binary, quoted-printable, base64; canonical form with CRLF.
- S/MIME 4.0, RFC 8551 (April 2019): authentication, integrity, non-repudiation (signatures); confidentiality (encryption); compression.
- Forms: enveloped, signed, clear-signed (
multipart/signed, readable by anyone), signed and enveloped, compressed. Types:application/pkcs7-mimewithsmime-type;application/pkcs7-signature. - Signing: canonicalise, digest, signed attributes (content type, signing time, digest, capabilities), sign the attributes, pack in CMS SignedData.
- Algorithms: SHA-256 and SHA-512; ECDSA P-256 or EdDSA (RSA PKCS #1 v1.5 MUST-); ECDH P-256 and X25519; AES-128 and AES-256 GCM.
- Certificates: X.509 v3, email address in the subject alternative name.
- RFC 2634: triple wrapping, signed receipts, security labels, secure mailing lists, signing certificate.
- PGP against S/MIME: same cryptography, different trust (web of trust against CAs) and different formats.
Test yourself
1. What limitations of RFC 822 mail did MIME remove? RFC 822 mail could carry only text in US-ASCII: it had no provision for non-text content such as images, audio or programs, no way to carry the character sets needed for most languages, and mail systems limited messages to relatively short lines of 7-bit ASCII. MIME added typed content, character sets, multipart messages and transfer encodings that make any data safe for mail.
2. Name MIME's five header fields. MIME-Version, Content-Type, Content-Transfer-Encoding, Content-ID and Content-Description.
3. Distinguish S/MIME's signed data from its clear-signed data. Signed data packs the content and its signature into one CMS object encoded in base64, so only an S/MIME-capable program can even read the content. Clear-signed data sends a multipart/signed message whose first part is the ordinary, readable content and whose second part is the detached signature, so anyone can read the message and only S/MIME-capable programs can verify it.
S/MIME
4. Describe how an S/MIME signed message is produced. The MIME entity is put into canonical form, with every line ending in a carriage return and line feed, and its SHA-256 digest is computed. The signed attributes are formed: the content type, the signing time, that digest and the sender's capabilities. These attributes are signed with the sender's private key, and the digest algorithm, the signer's certificate and the signature are packed into a CMS SignedData structure, which is attached to or wrapped around the content.
5. Why must the content be canonicalised before it is signed? Because mail systems and computers represent line endings differently and may change them in transit. Signing and verifying a single agreed form, with every line ending in a carriage return and a line feed, means the signature does not fail merely because line endings changed; a verifier that hashed the content as displayed would compute a different digest, as the run demonstrates.
6. Compare S/MIME with PGP. Both use the same cryptographic approach: a signature over a hash of the message, made with the sender's private key, and a one-time symmetric key that encrypts the message and is itself encrypted for each recipient. They differ in how trust in public keys is established, PGP by a web of trust or direct fingerprint checks and S/MIME by X.509 certificates from certification authorities, and in their formats, OpenPGP packets with radix-64 armor against MIME entities wrapped in CMS. S/MIME's reliance on certification authorities suits organisations that already run or buy certificates; PGP needs no authority at all.
7. What are the enhanced security services of RFC 2634? Services built on triple wrapping, a message signed, encrypted and signed again: signed receipts, which prove a message was received and its signature checked; security labels, signed classifications used for access control; secure mailing lists, in which a list agent re-encrypts a message for each member; and the signing certificate attribute, which binds the signature to the exact certificate used.
The rest of this subject
These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.