1# -*- coding: utf-8 -*- 2# 3# (c) 2019, Felix Fontein <felix@fontein.de> 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17 18from __future__ import absolute_import, division, print_function 19__metaclass__ = type 20 21 22PEM_START = '-----BEGIN ' 23PEM_END = '-----' 24PKCS8_PRIVATEKEY_NAMES = ('PRIVATE KEY', 'ENCRYPTED PRIVATE KEY') 25PKCS1_PRIVATEKEY_SUFFIX = ' PRIVATE KEY' 26 27 28def identify_pem_format(content): 29 '''Given the contents of a binary file, tests whether this could be a PEM file.''' 30 try: 31 lines = content.decode('utf-8').splitlines(False) 32 if lines[0].startswith(PEM_START) and lines[0].endswith(PEM_END) and len(lines[0]) > len(PEM_START) + len(PEM_END): 33 return True 34 except UnicodeDecodeError: 35 pass 36 return False 37 38 39def identify_private_key_format(content): 40 '''Given the contents of a private key file, identifies its format.''' 41 # See https://github.com/openssl/openssl/blob/master/crypto/pem/pem_pkey.c#L40-L85 42 # (PEM_read_bio_PrivateKey) 43 # and https://github.com/openssl/openssl/blob/master/include/openssl/pem.h#L46-L47 44 # (PEM_STRING_PKCS8, PEM_STRING_PKCS8INF) 45 try: 46 lines = content.decode('utf-8').splitlines(False) 47 if lines[0].startswith(PEM_START) and lines[0].endswith(PEM_END) and len(lines[0]) > len(PEM_START) + len(PEM_END): 48 name = lines[0][len(PEM_START):-len(PEM_END)] 49 if name in PKCS8_PRIVATEKEY_NAMES: 50 return 'pkcs8' 51 if len(name) > len(PKCS1_PRIVATEKEY_SUFFIX) and name.endswith(PKCS1_PRIVATEKEY_SUFFIX): 52 return 'pkcs1' 53 return 'unknown-pem' 54 except UnicodeDecodeError: 55 pass 56 return 'raw' 57 58 59def split_pem_list(text, keep_inbetween=False): 60 ''' 61 Split concatenated PEM objects into a list of strings, where each is one PEM object. 62 ''' 63 result = [] 64 current = [] if keep_inbetween else None 65 for line in text.splitlines(True): 66 if line.strip(): 67 if not keep_inbetween and line.startswith('-----BEGIN '): 68 current = [] 69 if current is not None: 70 current.append(line) 71 if line.startswith('-----END '): 72 result.append(''.join(current)) 73 current = [] if keep_inbetween else None 74 return result 75