1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python 2*6777b538SAndroid Build Coastguard Worker# Copyright 2015 The Chromium Authors 3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 5*6777b538SAndroid Build Coastguard Worker 6*6777b538SAndroid Build Coastguard Worker"""This file contains helpers for representing, manipulating, and writing 7*6777b538SAndroid Build Coastguard WorkerOpenSSL configuration files [1] 8*6777b538SAndroid Build Coastguard Worker 9*6777b538SAndroid Build Coastguard WorkerConfiguration files are simply a collection of name=value "properties", which 10*6777b538SAndroid Build Coastguard Workerare grouped into "sections". 11*6777b538SAndroid Build Coastguard Worker 12*6777b538SAndroid Build Coastguard Worker[1] https://www.openssl.org/docs/manmaster/apps/config.html 13*6777b538SAndroid Build Coastguard Worker""" 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard Workerclass Property(object): 16*6777b538SAndroid Build Coastguard Worker """Represents a key/value pair in OpenSSL .cnf files. 17*6777b538SAndroid Build Coastguard Worker 18*6777b538SAndroid Build Coastguard Worker Names and values are not quoted in any way, so callers need to pass the text 19*6777b538SAndroid Build Coastguard Worker exactly as it should be written to the file (leading and trailing whitespace 20*6777b538SAndroid Build Coastguard Worker doesn't matter). 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard Worker For instance: 23*6777b538SAndroid Build Coastguard Worker baseConstraints = critical, CA:false 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard Worker Could be represented by a Property where: 26*6777b538SAndroid Build Coastguard Worker name = 'baseConstraints' 27*6777b538SAndroid Build Coastguard Worker value = 'critical, CA:false' 28*6777b538SAndroid Build Coastguard Worker """ 29*6777b538SAndroid Build Coastguard Worker def __init__(self, name, value): 30*6777b538SAndroid Build Coastguard Worker self.name = name 31*6777b538SAndroid Build Coastguard Worker self.value = value 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard Worker def write_to(self, out): 35*6777b538SAndroid Build Coastguard Worker """Outputs this property to .cnf file.""" 36*6777b538SAndroid Build Coastguard Worker out.write('%s = %s\n' % (self.name, self.value)) 37*6777b538SAndroid Build Coastguard Worker 38*6777b538SAndroid Build Coastguard Worker 39*6777b538SAndroid Build Coastguard Workerclass Section(object): 40*6777b538SAndroid Build Coastguard Worker """Represents a section in OpenSSL. For instance: 41*6777b538SAndroid Build Coastguard Worker [CA_root] 42*6777b538SAndroid Build Coastguard Worker preserve = true 43*6777b538SAndroid Build Coastguard Worker 44*6777b538SAndroid Build Coastguard Worker Could be represented by a Section where: 45*6777b538SAndroid Build Coastguard Worker name = 'CA_root' 46*6777b538SAndroid Build Coastguard Worker properties = [Property('preserve', 'true')] 47*6777b538SAndroid Build Coastguard Worker """ 48*6777b538SAndroid Build Coastguard Worker def __init__(self, name): 49*6777b538SAndroid Build Coastguard Worker self.name = name 50*6777b538SAndroid Build Coastguard Worker self.properties = [] 51*6777b538SAndroid Build Coastguard Worker 52*6777b538SAndroid Build Coastguard Worker 53*6777b538SAndroid Build Coastguard Worker def ensure_property_name_not_duplicated(self, name): 54*6777b538SAndroid Build Coastguard Worker """Raises an exception of there is more than 1 property named |name|.""" 55*6777b538SAndroid Build Coastguard Worker count = 0 56*6777b538SAndroid Build Coastguard Worker for prop in self.properties: 57*6777b538SAndroid Build Coastguard Worker if prop.name == name: 58*6777b538SAndroid Build Coastguard Worker count += 1 59*6777b538SAndroid Build Coastguard Worker if count > 1: 60*6777b538SAndroid Build Coastguard Worker raise Exception('Duplicate property: %s' % (name)) 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker 63*6777b538SAndroid Build Coastguard Worker def set_property(self, name, value): 64*6777b538SAndroid Build Coastguard Worker """Replaces, adds, or removes a Property from the Section: 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Worker - If |value| is None, then this is equivalent to calling 67*6777b538SAndroid Build Coastguard Worker remove_property(name) 68*6777b538SAndroid Build Coastguard Worker - If there is an existing property matching |name| then its value is 69*6777b538SAndroid Build Coastguard Worker replaced with |value| 70*6777b538SAndroid Build Coastguard Worker - If there are no properties matching |name| then a new one is added at 71*6777b538SAndroid Build Coastguard Worker the end of the section 72*6777b538SAndroid Build Coastguard Worker 73*6777b538SAndroid Build Coastguard Worker It is expected that there is AT MOST 1 property with the given name. If 74*6777b538SAndroid Build Coastguard Worker that is not the case then this function will raise an error.""" 75*6777b538SAndroid Build Coastguard Worker 76*6777b538SAndroid Build Coastguard Worker if value is None: 77*6777b538SAndroid Build Coastguard Worker self.remove_property(name) 78*6777b538SAndroid Build Coastguard Worker return 79*6777b538SAndroid Build Coastguard Worker 80*6777b538SAndroid Build Coastguard Worker self.ensure_property_name_not_duplicated(name) 81*6777b538SAndroid Build Coastguard Worker 82*6777b538SAndroid Build Coastguard Worker for prop in self.properties: 83*6777b538SAndroid Build Coastguard Worker if prop.name == name: 84*6777b538SAndroid Build Coastguard Worker prop.value = value 85*6777b538SAndroid Build Coastguard Worker return 86*6777b538SAndroid Build Coastguard Worker 87*6777b538SAndroid Build Coastguard Worker self.add_property(name, value) 88*6777b538SAndroid Build Coastguard Worker 89*6777b538SAndroid Build Coastguard Worker 90*6777b538SAndroid Build Coastguard Worker def add_property(self, name, value): 91*6777b538SAndroid Build Coastguard Worker """Adds a property (allows duplicates)""" 92*6777b538SAndroid Build Coastguard Worker self.properties.append(Property(name, value)) 93*6777b538SAndroid Build Coastguard Worker 94*6777b538SAndroid Build Coastguard Worker 95*6777b538SAndroid Build Coastguard Worker def remove_property(self, name): 96*6777b538SAndroid Build Coastguard Worker """Removes the property with the indicated name, if it exists. 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Worker It is expected that there is AT MOST 1 property with the given name. If 99*6777b538SAndroid Build Coastguard Worker that is not the case then this function will raise an error.""" 100*6777b538SAndroid Build Coastguard Worker self.ensure_property_name_not_duplicated(name) 101*6777b538SAndroid Build Coastguard Worker 102*6777b538SAndroid Build Coastguard Worker for i in range(len(self.properties)): 103*6777b538SAndroid Build Coastguard Worker if self.properties[i].name == name: 104*6777b538SAndroid Build Coastguard Worker self.properties.pop(i) 105*6777b538SAndroid Build Coastguard Worker return 106*6777b538SAndroid Build Coastguard Worker 107*6777b538SAndroid Build Coastguard Worker 108*6777b538SAndroid Build Coastguard Worker def clear_properties(self): 109*6777b538SAndroid Build Coastguard Worker """Removes all configured properties.""" 110*6777b538SAndroid Build Coastguard Worker self.properties = [] 111*6777b538SAndroid Build Coastguard Worker 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard Worker def write_to(self, out): 114*6777b538SAndroid Build Coastguard Worker """Outputs the section in the format used by .cnf files""" 115*6777b538SAndroid Build Coastguard Worker out.write('[%s]\n' % (self.name)) 116*6777b538SAndroid Build Coastguard Worker for prop in self.properties: 117*6777b538SAndroid Build Coastguard Worker prop.write_to(out) 118*6777b538SAndroid Build Coastguard Worker out.write('\n') 119*6777b538SAndroid Build Coastguard Worker 120*6777b538SAndroid Build Coastguard Worker 121*6777b538SAndroid Build Coastguard Workerclass Config(object): 122*6777b538SAndroid Build Coastguard Worker """Represents a .cnf (configuration) file in OpenSSL""" 123*6777b538SAndroid Build Coastguard Worker def __init__(self): 124*6777b538SAndroid Build Coastguard Worker self.sections = [] 125*6777b538SAndroid Build Coastguard Worker 126*6777b538SAndroid Build Coastguard Worker 127*6777b538SAndroid Build Coastguard Worker def get_section(self, name): 128*6777b538SAndroid Build Coastguard Worker """Gets or creates a section with the given name.""" 129*6777b538SAndroid Build Coastguard Worker for section in self.sections: 130*6777b538SAndroid Build Coastguard Worker if section.name == name: 131*6777b538SAndroid Build Coastguard Worker return section 132*6777b538SAndroid Build Coastguard Worker new_section = Section(name) 133*6777b538SAndroid Build Coastguard Worker self.sections.append(new_section) 134*6777b538SAndroid Build Coastguard Worker return new_section 135*6777b538SAndroid Build Coastguard Worker 136*6777b538SAndroid Build Coastguard Worker 137*6777b538SAndroid Build Coastguard Worker def write_to_file(self, path): 138*6777b538SAndroid Build Coastguard Worker """Outputs the Config to a .cnf files.""" 139*6777b538SAndroid Build Coastguard Worker with open(path, 'w') as out: 140*6777b538SAndroid Build Coastguard Worker for section in self.sections: 141*6777b538SAndroid Build Coastguard Worker section.write_to(out) 142