7.9
 )q    	#
# Copyright 2008 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#      http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Keyczart(ool) is a utility for creating and managing Keyczar keysets.

@author: arkajit.dey@gmail.com (Arkajit Dey)
"""

import os
import sys

import errors
import keyczar
import keydata
import keyinfo
import readers
import writers
import util

KEYSETS = [('aes', keyinfo.DECRYPT_AND_ENCRYPT, None, None),
           ('aes-crypted', keyinfo.DECRYPT_AND_ENCRYPT, None, 'aes'),
           ('hmac', keyinfo.SIGN_AND_VERIFY, None, None),
           ('rsa', keyinfo.DECRYPT_AND_ENCRYPT, 'rsa', None),
           ('rsa-sign', keyinfo.SIGN_AND_VERIFY, 'rsa', None),
           ('dsa', keyinfo.SIGN_AND_VERIFY, 'dsa', None)]

mock = None  # mock reader used for testing purposes, disabled when set to None

class _Name(object):
  
  def __init__(self, name):
    self.name = name
  
  def __str__(self):
    return self.name

class Command(_Name):
  """Enum representing keyczart commands."""

CREATE = Command("create")
ADDKEY = Command("addkey")
PUBKEY = Command("pubkey")
PROMOTE = Command("promote")
DEMOTE = Command("demote")
REVOKE = Command("revoke")
GENKEY = Command("genkey")
commands = {"create": CREATE, "addkey": ADDKEY, "pubkey": PUBKEY, 
            "promote": PROMOTE, "demote": DEMOTE, "revoke": REVOKE, 
            "genkey": GENKEY}

def GetCommand(cmd):
  try:
    return commands[cmd]
  except KeyError:
    raise errors.KeyczarError("Illegal command")

class Flag(_Name):
  """Enum representing keyczart flags."""

LOCATION = Flag("location")
NAME = Flag("name")
SIZE = Flag("size")
STATUS = Flag("status")
PURPOSE = Flag("purpose")
DESTINATION = Flag("destination")
VERSION = Flag("version")
ASYMMETRIC = Flag("asymmetric")
CRYPTER = Flag("crypter")
flags = {"location": LOCATION, "name": NAME, "size": SIZE, "status": STATUS,
         "purpose": PURPOSE, "destination": DESTINATION, "version": VERSION,
         "asymmetric": ASYMMETRIC, "crypter": CRYPTER}

def GetFlag(flag):
  try:
    return flags[flag]
  except KeyError:
    raise errors.KeyczarError("Unknown flag")

def Create(loc, name, purpose, asymmetric=None):
  if mock is None and loc is None:  # not testing
    raise errors.KeyczarError("Location missing")
  
  kmd = None
  if purpose == keyinfo.SIGN_AND_VERIFY:
    if asymmetric is None:
      kmd = keydata.KeyMetadata(name, purpose, keyinfo.HMAC_SHA1)
    elif asymmetric.lower() == "rsa":
      kmd = keydata.KeyMetadata(name, purpose, keyinfo.RSA_PRIV)
    else:  # default to DSA
      kmd = keydata.KeyMetadata(name, purpose, keyinfo.DSA_PRIV)
  elif purpose == keyinfo.DECRYPT_AND_ENCRYPT:
    if asymmetric is None:
      kmd = keydata.KeyMetadata(name, purpose, keyinfo.AES)
    else:  # default to RSA
      kmd = keydata.KeyMetadata(name, purpose, keyinfo.RSA_PRIV)
  else:
    raise errors.KeyczarError("Missing or unsupported purpose")
  
  if mock is not None:  # just testing, update mock object
    mock.kmd = kmd
  else:
    writer = writers.CreateWriter(loc)
    try:
      writer.WriteMetadata(kmd, overwrite=False)
    finally:
      writer.Close()

def AddKey(loc, status, crypter=None, size=None):
  czar = CreateGenericKeyczar(loc, crypter)
  if size == -1:
    size = None
  czar.AddVersion(status, size)
  UpdateGenericKeyczar(czar, loc, crypter)

def PubKey(loc, dest):
  if mock is None and dest is None:  # not required when testing
    raise errors.KeyczarError("Must define destination")
  czar = CreateGenericKeyczar(loc)
  czar.PublicKeyExport(dest, mock)  # supply mock for testing if enabled

def Promote(loc, num):
  czar = Creat