aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/crypto/cmsdetach80
1 files changed, 80 insertions, 0 deletions
diff --git a/contrib/crypto/cmsdetach b/contrib/crypto/cmsdetach
new file mode 100755
index 000000000..007500996
--- /dev/null
+++ b/contrib/crypto/cmsdetach
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+
+"""Detach CMS encrypted data.
+
+Detach encrypted data from a CMS envelopedData or authEnvelopedData
+message into a separate file.
+"""
+
+import argparse
+
+import asn1
+
+# Parse command-line arguments
+#
+parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+)
+parser.add_argument("-d", "--data", metavar="FILE",
+ help="Write detached data (without envelope) to FILE")
+parser.add_argument("-e", "--envelope", metavar="FILE",
+ help="Write envelope (without data) to FILE")
+parser.add_argument("-o", "--overwrite", action="store_true",
+ help="Overwrite output files")
+parser.add_argument("file", help="Input envelope file")
+args = parser.parse_args()
+if args.data is None and args.envelope is None:
+ parser.error("at least one of --data and --envelope is required")
+outmode = "wb" if args.overwrite else "xb"
+
+# Create decoder
+#
+decoder = asn1.Decoder()
+with open(args.file, mode="rb") as fh:
+ decoder.start(fh.read())
+
+# Create encoder
+#
+encoder = asn1.Encoder()
+encoder.start()
+
+# Detach encrypted data
+#
+data = None
+datastack = [
+ asn1.Numbers.Sequence, 0, asn1.Numbers.Sequence, asn1.Numbers.Sequence
+]
+stack = []
+while stack or not decoder.eof():
+ if decoder.eof():
+ encoder.leave()
+ decoder.leave()
+ stack.pop()
+ else:
+ tag = decoder.peek()
+ if tag.typ == asn1.Types.Constructed:
+ encoder.enter(nr=tag.nr, cls=tag.cls)
+ decoder.enter()
+ stack.append(tag.nr)
+ else:
+ (tag, value) = decoder.read()
+ if stack == datastack and tag.nr == 0:
+ data = value
+ else:
+ encoder.write(value, nr=tag.nr, cls=tag.cls)
+envelope = encoder.output()
+if data is None:
+ parser.error("Input file does not contain any encrypted data")
+
+# Write envelope (without data), if applicable
+#
+if args.envelope:
+ with open(args.envelope, mode=outmode) as fh:
+ fh.write(envelope)
+
+# Write data (without envelope), if applicable
+#
+if args.data:
+ with open(args.data, mode=outmode) as fh:
+ fh.write(data)