1# Author: Trevor Perrin
2# See the LICENSE file for legal information regarding use of this file.
3
4from .compat import *
5import binascii
6
7#This code is shared with tackpy (somewhat), so I'd rather make minimal
8#changes, and preserve the use of a2b_base64 throughout.
9
10def dePem(s, name):
11    """Decode a PEM string into a bytearray of its payload.
12
13    The input must contain an appropriate PEM prefix and postfix
14    based on the input name string, e.g. for name="CERTIFICATE"::
15
16      -----BEGIN CERTIFICATE-----
17      MIIBXDCCAUSgAwIBAgIBADANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQDEwRUQUNL
18      ...
19      KoZIhvcNAQEFBQADAwA5kw==
20      -----END CERTIFICATE-----
21
22    The first such PEM block in the input will be found, and its
23    payload will be base64 decoded and returned.
24    """
25    prefix  = "-----BEGIN %s-----" % name
26    postfix = "-----END %s-----" % name
27    start = s.find(prefix)
28    if start == -1:
29        raise SyntaxError("Missing PEM prefix")
30    end = s.find(postfix, start+len(prefix))
31    if end == -1:
32        raise SyntaxError("Missing PEM postfix")
33    s = s[start+len("-----BEGIN %s-----" % name) : end]
34    retBytes = a2b_base64(s) # May raise SyntaxError
35    return retBytes
36
37def dePemList(s, name):
38    """Decode a sequence of PEM blocks into a list of bytearrays.
39
40    The input must contain any number of PEM blocks, each with the appropriate
41    PEM prefix and postfix based on the input name string, e.g. for
42    name="TACK BREAK SIG".  Arbitrary text can appear between and before and
43    after the PEM blocks.  For example::
44
45        Created by TACK.py 0.9.3 Created at 2012-02-01T00:30:10Z
46        -----BEGIN TACK BREAK SIG-----
47        ATKhrz5C6JHJW8BF5fLVrnQss6JnWVyEaC0p89LNhKPswvcC9/s6+vWLd9snYTUv
48        YMEBdw69PUP8JB4AdqA3K6Ap0Fgd9SSTOECeAKOUAym8zcYaXUwpk0+WuPYa7Zmm
49        SkbOlK4ywqt+amhWbg9txSGUwFO5tWUHT3QrnRlE/e3PeNFXLx5Bckg=
50        -----END TACK BREAK SIG-----
51        Created by TACK.py 0.9.3 Created at 2012-02-01T00:30:11Z
52        -----BEGIN TACK BREAK SIG-----
53        ATKhrz5C6JHJW8BF5fLVrnQss6JnWVyEaC0p89LNhKPswvcC9/s6+vWLd9snYTUv
54        YMEBdw69PUP8JB4AdqA3K6BVCWfcjN36lx6JwxmZQncS6sww7DecFO/qjSePCxwM
55        +kdDqX/9/183nmjx6bf0ewhPXkA0nVXsDYZaydN8rJU1GaMlnjcIYxY=
56        -----END TACK BREAK SIG-----
57
58    All such PEM blocks will be found, decoded, and return in an ordered list
59    of bytearrays, which may have zero elements if not PEM blocks are found.
60    """
61    bList = []
62    prefix  = "-----BEGIN %s-----" % name
63    postfix = "-----END %s-----" % name
64    while 1:
65        start = s.find(prefix)
66        if start == -1:
67            return bList
68        end = s.find(postfix, start+len(prefix))
69        if end == -1:
70            raise SyntaxError("Missing PEM postfix")
71        s2 = s[start+len(prefix) : end]
72        retBytes = a2b_base64(s2) # May raise SyntaxError
73        bList.append(retBytes)
74        s = s[end+len(postfix) : ]
75
76def pem(b, name):
77    """Encode a payload bytearray into a PEM string.
78
79    The input will be base64 encoded, then wrapped in a PEM prefix/postfix
80    based on the name string, e.g. for name="CERTIFICATE"::
81
82        -----BEGIN CERTIFICATE-----
83        MIIBXDCCAUSgAwIBAgIBADANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQDEwRUQUNL
84        ...
85        KoZIhvcNAQEFBQADAwA5kw==
86        -----END CERTIFICATE-----
87    """
88    s1 = b2a_base64(b)[:-1] # remove terminating \n
89    s2 = ""
90    while s1:
91        s2 += s1[:64] + "\n"
92        s1 = s1[64:]
93    s = ("-----BEGIN %s-----\n" % name) + s2 + \
94        ("-----END %s-----\n" % name)
95    return s
96
97def pemSniff(inStr, name):
98    searchStr = "-----BEGIN %s-----" % name
99    return searchStr in inStr
100