Skip to content

Instantly share code, notes, and snippets.

@5HT
Created January 14, 2026 21:24
Show Gist options
  • Select an option

  • Save 5HT/7201247a23c9927b98d2ecd378f936af to your computer and use it in GitHub Desktop.

Select an option

Save 5HT/7201247a23c9927b98d2ecd378f936af to your computer and use it in GitHub Desktop.
# CMS AUTH aka CMC
Show basic code in Swift how to perform CMS AUTH, CMC I believe it is called?
```
AuthenticatedData ::= SEQUENCE {
version CMSVersion,
originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
recipientInfos RecipientInfos,
macAlgorithm MessageAuthenticationCodeAlgorithm,
digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
encapContentInfo EncapsulatedContentInfo,
authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
mac MessageAuthenticationCode,
unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
CMSVersion ::= INTEGER -- usually 0 for this content type
OriginatorInfo ::= SEQUENCE {
certs [0] IMPLICIT CertificateSet OPTIONAL,
crls [1] IMPLICIT CertificateRevocationLists OPTIONAL }
RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
MessageAuthenticationCodeAlgorithm ::= AlgorithmIdentifier{MAC-ALGORITHM,...}
DigestAlgorithmIdentifier ::= AlgorithmIdentifier{DIGEST-ALGORITHM,...}
EncapsulatedContentInfo ::= SEQUENCE {
eContentType ContentType,
eContent [0] EXPLICIT OCTET STRING OPTIONAL }
AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
-- MUST be DER-encoded if present
-- MUST include content-type + message-digest if eContentType ≠ id-data
MessageAuthenticationCode ::= OCTET STRING
UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
```
## Option 0
```
import SwiftASN1
import Crypto
import X509 // swift-certificates
struct AuthenticatedData: DERParseable, DERSerializable {
var version: Int
var originatorInfo: OriginatorInfo?
var recipientInfos: [RecipientInfo]
var macAlgorithm: AlgorithmIdentifier
var digestAlgorithm: AlgorithmIdentifier?
var encapContentInfo: EncapsulatedContentInfo
var authAttrs: [CMSAttribute]?
var mac: Data // OCTET STRING
var unauthAttrs: [CMSAttribute]?
// Implement parse(from:) and serialize(into:) according to ASN.1 above
// ...
}
func createSimpleAuthenticatedData(
content: Data,
contentType: ObjectIdentifier, // usually .data
macKey: SymmetricKey, // e.g. HMAC key
recipients: [RecipientInfoBuilder] // key transport / agreement / etc.
) throws -> Data {
let digestAlgo = AlgorithmIdentifier.algorithmIdentifier(.sha256)
// 1. Compute MAC input (content + authAttrs if present)
let macAlgo = AlgorithmIdentifier.algorithmIdentifier(.hmacWithSHA256)
// Minimal authAttrs: content-type + message-digest
let attrs = try buildRequiredAuthAttrs(contentType: contentType, content: content)
let attrsDER = try DER.Serializer.serialized { $0.serializeSequence { /* attrs */ } }
let macInput = content + attrsDER // simplified – real is more involved
let mac = HMAC<SHA256>.authenticationCode(for: macInput, using: macKey)
// 2. Build recipientInfos (encrypt macKey to each recipient)
let recipientInfos = try recipients.map { try $0.build(for: macKey) }
let authData = AuthenticatedData(
version: 0,
originatorInfo: nil,
recipientInfos: recipientInfos,
macAlgorithm: macAlgo,
digestAlgorithm: digestAlgo,
encapContentInfo: EncapsulatedContentInfo(eContentType: contentType, eContent: content),
authAttrs: attrs,
mac: Data(mac),
unauthAttrs: nil
)
let contentInfo = ContentInfo.authenticatedData(authData)
return try DER.Serializer.serialized { try contentInfo.serialize(into: &$0) }
}
```
## Option 1 – Modern pure-Swift approach (recommended 2025–2026)Use these Swift-native libraries together:
* swift-asn1 (from Apple or pointfreeco/swift-asn1) — for DER encoding
* swift-crypto — for hashing & signing
* swift-certificates — for X.509 certificate handling
Basic skeleton for creating a CMS SignedData (very simplified / incomplete — real implementation needs full SignedData → SignerInfo → SignedAttributes → digest + signature):
```swift
import Crypto
import X509 // from swift-certificates
import SwiftASN1
func createSimpleCMSSignedData(
content: Data,
signerCert: X509.Certificate,
signerKey: P384.Signing.PrivateKey // or P256 / RSA etc.
) throws -> Data {
// 1. Compute content digest (usually sha256)
let digest = SHA256.hash(data: content)
let digestBytes = Array(digest)
// 2. Prepare signed attributes (minimal set)
// You MUST include contentType + messageDigest + signingTime in real code
let signedAttrs: [CMSAttribute] = [
// contentType(1.2.840.113549.1.7.1) -- Data
// message-digest = digestBytes
// signing-time = now
]
let signedAttrsDER = try DER.Serializer.serialized { coder in
try coder.serializeSequence {
for attr in signedAttrs { try attr.serialize(into: &coder) }
}
}
// 3. Hash signed attributes (IMPLICIT SET → DER)
let signedAttrsDigest = SHA256.hash(data: signedAttrsDER)
// 4. Sign the digest of signed attributes
let signature = try signerKey.signature(for: signedAttrsDigest)
// 5. Build SignerInfo
let signerInfo = CMSSignerInfo(
version: .v1,
sid: .issuerAndSerialNumber(
issuer: signerCert.issuer,
serialNumber: signerCert.serialNumber
),
digestAlgorithm: .sha256,
signedAttrs: signedAttrs,
signatureAlgorithm: .ecdsaP384sha384, // match your key
signature: signature.rawRepresentation
)
// 6. Build SignedData
let signedData = CMSSignedData(
version: .v1,
digestAlgorithms: [.sha256],
encapContentInfo: .data(content),
certificates: [signerCert],
signerInfos: [signerInfo]
)
// 7. Wrap in ContentInfo
let contentInfo = CMSContentInfo.signedData(signedData)
// 8. DER-encode everything
let der = try DER.Serializer.serialized {
try contentInfo.serialize(into: &$0)
}
return Data(der)
}
```
## Option 2 – If you really want Apple's high-level CMS API (macOS only)
```
// macOS only – does NOT compile on iOS
import Security
func createCMSSignedDataMacOS(
data: Data,
identity: SecIdentity
) throws -> Data {
var encoder: CMSEncoder?
var status = CMSEncoderCreate(&encoder)
guard status == errSecSuccess, let encoder else {
throw NSError(domain: NSOSStatusErrorDomain, code: Int(status))
}
status = CMSEncoderSetDetachedContent(encoder, false)
status = CMSEncoderAddSigners(encoder, identity)
// Optional: add more options (timestamp, etc.)
// CMSEncoderAddBinaryHeader(…)
var encodedData: CFData?
status = CMSEncoderCopyEncodedContent(encoder, data as CFData, &encodedData)
guard status == errSecSuccess, let encoded = encodedData as? Data else {
throw NSError(domain: NSOSStatusErrorDomain, code: Int(status))
}
return encoded
}
```
## Option 3. Simple ECDSA
```
import Crypto
func simpleDetachedSignature(
data: Data,
privateKey: P384.Signing.PrivateKey
) throws -> Data {
let signature = try privateKey.signature(for: data)
return signature.rawRepresentation // DER-encoded ECDSA signature
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment