Browse Source

[crypto] Switch to using python-asn1crypto instead of python-asn1

Version 3.0.0 of python-asn1 has a serious defect that causes it to
generate invalid DER.

Fix by switching to the asn1crypto module, which also allows for
simpler code to be used.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/1444/head
Michael Brown 2 months ago
parent
commit
96dfaa7e7a
  1. 62
      contrib/crypto/cmsdetach

62
contrib/crypto/cmsdetach

@ -7,8 +7,9 @@ message into a separate file.
""" """
import argparse import argparse
from pathlib import Path
import asn1
from asn1crypto.cms import ContentInfo, AuthEnvelopedData, EnvelopedData
# Parse command-line arguments # Parse command-line arguments
# #
@ -16,64 +17,45 @@ parser = argparse.ArgumentParser(
description=__doc__, description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
) )
parser.add_argument("-d", "--data", metavar="FILE",
parser.add_argument("-d", "--data", metavar="FILE", type=Path,
help="Write detached data (without envelope) to FILE") help="Write detached data (without envelope) to FILE")
parser.add_argument("-e", "--envelope", metavar="FILE",
parser.add_argument("-e", "--envelope", metavar="FILE", type=Path,
help="Write envelope (without data) to FILE") help="Write envelope (without data) to FILE")
parser.add_argument("-o", "--overwrite", action="store_true", parser.add_argument("-o", "--overwrite", action="store_true",
help="Overwrite output files") help="Overwrite output files")
parser.add_argument("file", help="Input envelope file")
parser.add_argument("file", type=Path, help="Input envelope file")
args = parser.parse_args() args = parser.parse_args()
if args.data is None and args.envelope is None: if args.data is None and args.envelope is None:
parser.error("at least one of --data and --envelope is required") parser.error("at least one of --data and --envelope is required")
outmode = "wb" if args.overwrite else "xb" outmode = "wb" if args.overwrite else "xb"
# Create decoder
# Read input envelope
# #
decoder = asn1.Decoder()
with open(args.file, mode="rb") as fh:
decoder.start(fh.read())
envelope = ContentInfo.load(args.file.read_bytes())
# Create encoder
# Locate encrypted content info
# #
encoder = asn1.Encoder()
encoder.start()
content = envelope["content"]
if type(content) is AuthEnvelopedData:
encinfo = content["auth_encrypted_content_info"]
elif type(content) is EnvelopedData:
encinfo = content["encrypted_content_info"]
else:
parser.error("Input file does not contain any encrypted data")
# Detach encrypted data
# Detach encrypted content data
# #
data = None
datastack = [
asn1.Numbers.Sequence, 0, asn1.Numbers.Sequence, asn1.Numbers.Sequence
]
stack = []
while stack or not decoder.eof():
tag = decoder.peek()
if tag is None:
encoder.leave()
decoder.leave()
stack.pop()
elif 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")
data = encinfo["encrypted_content"]
del encinfo["encrypted_content"]
# Write envelope (without data), if applicable # Write envelope (without data), if applicable
# #
if args.envelope: if args.envelope:
with open(args.envelope, mode=outmode) as fh:
fh.write(envelope)
with args.envelope.open(mode=outmode) as fh:
fh.write(envelope.dump())
# Write data (without envelope), if applicable # Write data (without envelope), if applicable
# #
if args.data: if args.data:
with open(args.data, mode=outmode) as fh:
fh.write(data)
with args.data.open(mode=outmode) as fh:
fh.write(data.contents)
Loading…
Cancel
Save