aboutsummaryrefslogtreecommitdiff
path: root/scripts/rpki/cms.py
blob: a00d3ba29751b836837f009ff1843929d2e3060d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# $Id$

"""CMS routines.

For the moment these just call the OpenSSL CLI tool, which is slow,
requires disk I/O, and likes PEM format.  Fix this later.
"""

import os, rpki.x509

# openssl smime -sign -nodetach -outform DER -signer biz-certs/Alice-EE.cer -certfile biz-certs/Alice-CA.cer -inkey biz-certs/Alice-EE.key -in PLAN -out PLAN.der

def encode(xml, key, cert_files):
  """Encode a chunk of XML as CMS signed with a specified key and bag of certificates.

  We have to sort the certificates into the correct order before the
  OpenSSL CLI tool will accept them.  rpki.x509 handles that for us.
  """

  certs = rpki.x509.X509_chain()
  certs.load_from_PEM(cert_files)
  certs.chainsort()

  signer_filename = "cms.tmp.signer.pem"
  certfile_filename = "cms.tmp.certfile.pem"
  
  f = open(signer_filename, "w")
  f.write(certs[0].get_PEM())
  f.close()

  f = open(certfile_filename, "w")
  for cert in certs[1:]:
    f.write(cert.get_PEM())
  f.close()

  i,o = os.popen2(["openssl", "smime", "-sign", "-nodetach", "-outform", "DER", "-signer", signer_filename, "-certfile", certfile_filename, "-inkey", key])
  i.write(xml)
  i.close()
  cms = o.read()
  o.close()

  os.unlink(signer_filename)
  os.unlink(certfile_filename)

  return cms

# openssl smime -verify -inform DER -in PLAN.der -CAfile biz-certs/Alice-Root.cer 

def decode(cms, ta):
  """Decode and check the signature of a chunk of CMS.

  Returns the signed text (XML, until proven otherwise) on success.
  if OpenSSL CLI tool reports anything other than successful
  verification, we raise an exception.
  """  

  i,o,e = os.popen3(["openssl", "smime", "-verify", "-inform", "DER", "-CAfile", ta])
  i.write(cms)
  i.close()
  xml = o.read()
  o.close()
  status = e.read()
  e.close()
  if status == "Verification successful\n":
    return xml
  else:
    raise RuntimeError, "CMS verification failed: %s" % status