b8c7f237f0e0c519998ff8c52fa4c1558be6eee7
[sfa.git] / sfa / server / sfa-ca.py
1 #!/usr/bin/python
2
3 #
4 # SFA Certificate Signing and management. Root authorities can use this script 
5 # to sign  the certificate of another authority and become its parent. Sub 
6 # authorities (authorities that have had their cert signed by another authority) 
7 # can use this script to update their registry hierarchy with the new cert    
8
9 # Example usage: 
10 #
11 ## sign a peer cert
12 # sfa-ca.py --sign PEER_CERT_FILENAME -o OUTPUT_FILENAME 
13 #
14 ## import a cert and update the registry hierarchy
15 # sfa-ca.py --import CERT_FILENAME   
16 #
17 ## display a cert
18 # sfa-ca.py --display CERT_FILENAME
19
20
21 import os
22 import sys
23 from optparse import OptionParser
24 from sfa.trust.certificate import Keypair, Certificate
25 from sfa.trust.gid import GID, create_uuid
26 from sfa.trust.hierarchy import Hierarchy
27 from sfa.util.config import Config
28 from collections import defaultdict
29
30 def main():
31     args = sys.argv
32     script_name = args[0]
33     parser = OptionParser(usage="%(script_name)s [options]" % locals())
34     parser.add_option("-d", "--display", dest="display", default=None,
35                       help="print contents of specified gid")           
36     parser.add_option("-s", "--sign", dest="sign", default=None, 
37                       help="gid to sign" )
38     parser.add_option("-k", "--key", dest="key", default=None, 
39                       help="keyfile to use for signing")
40     parser.add_option("-a", "--authority", dest="authority", default=None, 
41                       help="sign the gid using the specified authority ")
42     parser.add_option("-i", "--import", dest="importgid", default=None,
43                       help="gid file to import into the registry")
44     parser.add_option("-e", "--export", dest="export", 
45                       help="name of gid to export from registry")
46     parser.add_option("-o", "--outfile", dest="outfile",
47                       help="where to write the exprted gid") 
48     parser.add_option("-v", "--verbose", dest="verbose", default=False, 
49                       action="store_true", help="be verbose")           
50                 
51     (options, args) = parser.parse_args()
52
53
54     if options.display:
55         display(options)
56     elif options.sign:
57         sign(options)
58     elif options.importgid:
59         import_gid(options) 
60     elif options.export:
61         export_gid(options)  
62     else:
63         parser.print_help()
64         sys.exit(1)        
65
66
67 def display(options):
68     """
69     Display the sepcified GID
70     """
71     gidfile = os.path.abspath(options.display)
72     if not gidfile or not os.path.isfile(gidfile):
73         print "No such gid: %s" % gidfile
74         sys.exit(1)
75     gid = GID(filename=gidfile)
76     gid.dump(dump_parents=True)
77
78 def sign_gid(gid, parent_key, parent_gid):
79     gid.set_issuer(parent_key, parent_gid.get_hrn())
80     gid.set_parent(parent_gid)
81     gid.set_intermediate_ca(True)
82     gid.set_pubkey(gid.get_pubkey())
83     gid.sign()
84     return gid 
85
86 def sign(options):
87     """
88     Sign the specified gid
89     """
90     hierarchy = Hierarchy()
91     config = Config()
92     default_authority = config.SFA_INTERFACE_HRN
93     auth_info = hierarchy.get_auth_info(default_authority)
94
95     # load the gid
96     gidfile = os.path.abspath(options.sign)
97     if not os.path.isfile(gidfile):
98         print "no such gid: %s" % gidfile
99         sys.exit(1)
100     gid = GID(filename=gidfile)
101
102     # remove previous parent
103     gid = GID(string=gid.save_to_string(save_parents=False))
104
105     # load the parent private info
106     authority = options.authority    
107     # if no pkey was specified, then use the this authority's key
108     if not authority:
109         authority = default_authority 
110     
111     if not hierarchy.auth_exists(authority):
112         print "no such authority: %s" % authority    
113
114     # load the parent gid and key 
115     auth_info = hierarchy.get_auth_info(authority)
116     pkeyfile = auth_info.privkey_filename
117     parent_key = Keypair(filename=pkeyfile)
118     parent_gid = auth_info.gid_object
119
120     # get the outfile
121     outfile = options.outfile
122     if not outfile:
123         outfile = os.path.abspath('./signed-%s.gid' % gid.get_hrn())
124    
125     # check if gid already has a parent
126  
127     # sign the gid
128     if options.verbose:
129         print "Signing %s gid with parent %s" % \
130               (gid.get_hrn(), parent_gid.get_hrn())
131     gid = sign_gid(gid, parent_key, parent_gid)
132     # save the signed gid
133     if options.verbose:
134         print "Writing signed gid %s" % outfile  
135     gid.save_to_file(outfile, save_parents=True)
136     
137
138 def export_gid(options):
139     from sfa.util.table import SfaTable
140     # lookup the record for the specified hrn 
141     hrn = options.export
142
143     # check sfa table first    
144     table = SfaTable()
145     records = table.find({'hrn': hrn, type: 'authority'})
146     if not records:
147         # check the authorities hierarchy 
148         hierarchy = Hierarchy()
149         try:
150             auth_info = hierarchy.get_auth_info()
151             gid = auth_info.gid_object 
152         except:
153             print "Record: %s not found" % hrn
154             sys.exit(1)
155     else:
156         record = records[0]
157         gid = GID(string=record['gid'])
158         
159     # get the outfile
160     outfile = options.outfile
161     if not outfile:
162         outfile = os.path.abspath('./%s.gid' % gid.get_hrn())
163
164     # save it
165     if options.verbose:
166         print "Writing %s gid to %s" % (gid.get_hrn(), outfile)
167     gid.save_to_file(outfile, save_parents=True)
168
169 def import_gid(options):
170     """
171     Import the specified gid into the registry (db and authorities 
172     hierarchy) overwriting any previous gid.
173     """
174     from sfa.util.table import SfaTable
175     from sfa.util.record import SfaRecord
176     # load the gid
177     gidfile = os.path.abspath(options.importgid)
178     if not gidfile or not os.path.isfile(gidfile):
179         print "No such gid: %s" % gidfile
180         sys.exit(1)
181     gid = GID(filename=gidfile)
182     
183     # check if it exists within the hierarchy
184     hierarchy = Hierarchy()
185     if not hierarchy.auth_exists(gid.get_hrn()):
186         print "%s not found in hierarchy" % gid.get_hrn()
187         sys.exit(1)
188
189     # check if record exists in db
190     table = SfaTable()
191     records = table.find({'hrn': gid.get_hrn(), 'type': 'authority'})
192     if not records:
193         print "%s not found in record database" % get.get_hrn()  
194         sys.exit(1)
195
196     # update the database record
197     record = records[0]
198     record['gid'] = gid.save_to_string(save_parents=True)
199     table.update(record)
200     if options.verbose:
201         print "Imported %s gid into db" % record['hrn']
202
203     # update the hierarchy
204     auth_info = hierarchy.get_auth_info(gid.get_hrn())  
205     filename = auth_info.gid_filename
206     gid.save_to_file(filename, save_parents=True)
207     if options.verbose:
208         print "Writing %s gid to %s" % (gid.get_hrn(), filename)
209
210     # re-sign all existing gids signed by this authority  
211     # create a dictionary of records keyed on the record's authority
212     record_dict = defaultdict(list)
213     # only get regords that belong to this authority 
214     # or any of its sub authorities   
215     child_records = table.find({'hrn': '%s*' % gid.get_hrn()})
216     if not child_records:
217         return
218   
219     for record in child_records:
220         record_dict[record['authority']].append(record) 
221
222     # start with the authority we just imported       
223     authorities = [gid.get_hrn()]
224     while authorities:
225         next_authorities = []
226         for authority in authorities:
227             # create a new signed gid for each record at this authority 
228             # and update the registry
229             auth_info = hierarchy.get_auth_info(authority)
230             records = record_dict[authority]
231             for record in records:
232                 record_gid = GID(string=record['gid'])
233                 parent_pkey = Keypair(filename=auth_info.privkey_filename)
234                 parent_gid = GID(filename=auth_info.gid_filename)
235                 if options.verbose:
236                     print "re-signing %s gid with parent %s" % \
237                            (record['hrn'], parent_gid.get_hrn())  
238                 signed_gid = sign_gid(record_gid, parent_pkey, parent_gid)
239                 record['gid'] = signed_gid.save_to_string(save_parents=True)
240                 table.update(record)
241                 
242                 # if this is an authority then update the hierarchy
243                 if record['type'] == 'authority':
244                     record_info = hierarchy.get_auth_info(record['hrn'])
245                     if options.verbose:
246                         print "Writing %s gid to %s" % (record['hrn'], record_info.gid_filename) 
247                     signed_gid.save_to_file(filename=record_info.gid_filename, save_parents=True)
248
249              # update list of next authorities
250             tmp_authorities = set([record['hrn'] for record in records \
251                                    if record['type'] == 'authority'])
252             next_authorities.extend(tmp_authorities)
253
254         # move on to next set of authorities
255         authorities = next_authorities     
256
257 if __name__ == '__main__':
258     main()