class ManifestV3

Manifest Version 3. Not backwards compatible

Manifest Version 3. Not backwards compatible

Constants

VERSION
VERSION_STRING

Public Class Methods

new( xml = nil ) click to toggle source
# File lib/ec2/amitools/manifestv3.rb, line 34
def initialize( xml = nil )
  if xml == nil
    @doc = REXML::Document.new
  else
    # Convert to string if necessary.
    xml = ( xml.kind_of?( IO ) ? xml.read : xml )
    @doc = REXML::Document.new( xml )
  end
end
version3?( xml ) click to toggle source
# File lib/ec2/amitools/manifestv3.rb, line 178
def ManifestV3::version3?( xml )
  doc = REXML::Document.new( xml )
  version = REXML::XPath.first( doc.root, 'version' )
  return (version and version.text and version.text.to_i == VERSION)
end

Public Instance Methods

ami_part_info_list() click to toggle source

Retrieve a list of AMI bundle parts info. Each element is a hash with the following elements:

  • 'digest'

  • 'filename'

  • 'index'

# File lib/ec2/amitools/manifestv3.rb, line 228
def ami_part_info_list
  parts = Array.new
  REXML::XPath.each( @doc.root,'image/parts/part' ) do |part|
    index = part.attribute( 'index' ).to_s.to_i
    filename = REXML::XPath.first( part, 'filename' ).text
    digest = REXML::XPath.first( part, 'digest' ).text
    parts << { 'digest'=>digest, 'filename'=>filename, 'index'=>index }
  end
  return parts
end
authenticate(cert) click to toggle source

Verify the signature

# File lib/ec2/amitools/manifestv3.rb, line 300
def authenticate(cert)
  image_xml = XMLUtil.get_xml( @doc.to_s, 'image' )
  pubkey = Crypto::cert2pubkey(cert)
  Crypto::authenticate(image_xml, Format::hex2bin(signature), pubkey)
end
bundled_size() click to toggle source

Return the bundled size of the AMI.

# File lib/ec2/amitools/manifestv3.rb, line 257
def bundled_size()
  return get_element_text( 'image/bundled_size' ).to_i
end
bundler_name() click to toggle source

Return the bundler name.

# File lib/ec2/amitools/manifestv3.rb, line 262
def bundler_name()
  return get_element_text('bundler/name')
end
bundler_release() click to toggle source

Return the bundler release.

# File lib/ec2/amitools/manifestv3.rb, line 272
def bundler_release()
  return get_element_text('bundler/release')
end
bundler_version() click to toggle source

Return the bundler version.

# File lib/ec2/amitools/manifestv3.rb, line 267
def bundler_version()
  return get_element_text('bundler/version')
end
cipher_algorithm() click to toggle source

Get cipher algorithm used.

# File lib/ec2/amitools/manifestv3.rb, line 219
def cipher_algorithm()
  return REXML::XPath.first(@doc.root, 'image/ec2_encrypted_key/@algorithm').to_s
end
digest() click to toggle source

Return the AMI's digest hex encoded.

# File lib/ec2/amitools/manifestv3.rb, line 185
def digest()
  return get_element_text( 'image/digest' )
end
digest_algorithm() click to toggle source

Get digest algorithm used.

# File lib/ec2/amitools/manifestv3.rb, line 214
def digest_algorithm()
  return REXML::XPath.first(@doc.root, 'image/digest/@algorithm').to_s
end
doc() click to toggle source

for debugging only

# File lib/ec2/amitools/manifestv3.rb, line 45
def doc
  @doc
end
ec2_encrypted_iv() click to toggle source

The ec2 encrypted initialization vector hex encoded.

# File lib/ec2/amitools/manifestv3.rb, line 204
def ec2_encrypted_iv()
  return get_element_text( 'image/ec2_encrypted_iv' )
end
ec2_encrypted_key() click to toggle source

The ec2 encrypted key hex encoded.

# File lib/ec2/amitools/manifestv3.rb, line 194
def ec2_encrypted_key()
  return get_element_text('image/ec2_encrypted_key' )
end
init( name, user, parts, size, bundled_size, user_encrypted_key, ec2_encrypted_key, cipher_algorithm, user_encrypted_iv, ec2_encrypted_iv, digest, digest_algorithm, privkey_filename, bundler_name = nil, bundler_version = nil, bundler_release = nil ) click to toggle source

Initialize the manifest with AMI information. Return true if the initialization was succesful. Raise an exception on error.

# File lib/ec2/amitools/manifestv3.rb, line 52
def init(
  name,
  user,                   # The user's account number.
  parts,                  # A list of parts filenames and digest pairs.
  size,                   # The size of the AMI in bytes.
  bundled_size,           # The size of the bunled AMI in bytes.
  user_encrypted_key,     # Hex encoded.
  ec2_encrypted_key,      # Hex encoded.
  cipher_algorithm,       # The cipher algorithm used to encrypted the AMI.
  user_encrypted_iv,      # Hex encoded.
  ec2_encrypted_iv,       # Hex encoded.
  digest,                 # Hex encoded.
  digest_algorithm,       # The digest algorithm.
  privkey_filename,       # The user's private key filename.
  bundler_name = nil,
  bundler_version = nil,
  bundler_release = nil )
  # Check non-String parameter types.
  raise ArgumentError.new( "parts parameter type invalid" ) unless parts.is_a? Array
      
  # XML document.
  @doc = REXML::Document.new
  @doc << REXML::XMLDecl.new

  # manifest - the root element.
  manifest = REXML::Element.new( 'manifest' )

  @doc.add_element( manifest )
  
  # version - indicate the manifest version.
  version = REXML::Element.new( 'version' )
  version.text = VERSION_STRING
  manifest.add_element( version )
  
  # bundler information
  if bundler_name or bundler_version or bundler_release
    bundler_element = REXML::Element.new( 'bundler' )
    manifest.add_element( bundler_element )
    
    [['name', bundler_name ], 
     ['version', bundler_version ],
     ['release', bundler_release ]].each do |element_name, text|
      if element_name
        element = REXML::Element.new( element_name )
        element.text = text
        bundler_element.add_element( element )
      end
    end 
  end
  
  # image - the image element.
  image = REXML::Element.new( 'image' )
  name_element = REXML::Element.new( 'name' )
  name_element.text = name
  image.add_element( name_element )
  manifest.add_element( image )
  
  # user - the user's AWS access key ID.
  user_element = REXML::Element.new( 'user' )
  user_element.text = user
  image.add_element( user_element )
  
  # digest - the digest of the AMI.
  digest_element = REXML::Element.new( 'digest' )
  digest_element.add_attribute( 'algorithm', digest_algorithm )
  digest_element.add_text( digest )
  image.add_element( digest_element )
  
  # size - the size of the uncompressed AMI.
  size_element = REXML::Element.new( 'size' )
  size_element.text = size.to_s
  image.add_element( size_element )
  
  # size - the size of the uncompressed AMI.
  bundled_size_element = REXML::Element.new( 'bundled_size' )
  bundled_size_element.text = bundled_size.to_s
  image.add_element( bundled_size_element )
  
  # ec2 encrypted key element.
  ec2_encrypted_key_element = REXML::Element.new( 'ec2_encrypted_key' )
  ec2_encrypted_key_element.add_attribute( 'algorithm', cipher_algorithm )
  ec2_encrypted_key_element.add_text( ec2_encrypted_key )
  image.add_element( ec2_encrypted_key_element )
  
  # user encrypted key element.
  user_encrypted_key_element = REXML::Element.new( 'user_encrypted_key' )
  user_encrypted_key_element.add_attribute( 'algorithm', cipher_algorithm )
  user_encrypted_key_element.add_text( user_encrypted_key )
  image.add_element( user_encrypted_key_element )
  
  # ec2 encrypted iv element.
  ec2_encrypted_iv_element = REXML::Element.new( 'ec2_encrypted_iv' )
  ec2_encrypted_iv_element.add_text( ec2_encrypted_iv )
  image.add_element( ec2_encrypted_iv_element )
  
  # user encrypted iv element.
  user_encrypted_iv_element = REXML::Element.new( 'user_encrypted_iv' )
  user_encrypted_iv_element.add_text( user_encrypted_iv )
  image.add_element( user_encrypted_iv_element )
  
  # parts - list of the image parts.
  parts_element = REXML::Element.new( 'parts' )
  parts_element.add_attributes( {'count' => parts.size.to_s} )
  index=0
  parts.each do |part|
    # Add image part element for each image part.
    part_element = REXML::Element.new( 'part' )
    part_element.add_attribute( 'index', index.to_s )
    filename = REXML::Element.new( 'filename' )
    filename.add_text( part[0] )
    part_element.add_element( filename )
    digest = REXML::Element.new( 'digest' )
    digest.add_attribute( 'algorithm', digest_algorithm )
    digest.add_text( Format::bin2hex( part[1] ) )
    part_element.add_element( digest )
    parts_element.add_element( part_element )
    index+=1
  end
  image.add_element( parts_element )

  # Sign the manifest.
  sign( privkey_filename )
  
  return true
end
name() click to toggle source
# File lib/ec2/amitools/manifestv3.rb, line 189
def name()
  return get_element_text( 'image/name' )
end
parts() click to toggle source

A list of PartInformation instances representing the AMI parts.

# File lib/ec2/amitools/manifestv3.rb, line 240
def parts()
  parts = []
  REXML::XPath.each( @doc.root,'image/parts/part' ) do |part|
    index = part.attribute( 'index' ).to_s.to_i
    filename = REXML::XPath.first( part, 'filename' ).text
    digest = Format::hex2bin(  REXML::XPath.first( part, 'digest' ).text  )
    parts[index] = PartInformation.new(  filename, digest  )
  end
  return parts
end
sign( privkey_filename ) click to toggle source

Sign the manifest. If it is already signed, the signature and certificate will be replaced

# File lib/ec2/amitools/manifestv3.rb, line 278
def sign( privkey_filename )
  unless privkey_filename.kind_of? String and File::exist?( privkey_filename )
    raise ArgumentError.new( "privkey_filename parameter invalid" )
  end
  
  # Get the XML for image element and sign it.
  image_xml = XMLUtil.get_xml( @doc.to_s, 'image' )
  sig = Crypto::sign( image_xml, privkey_filename )
       
  # Create the signature and certificate elements.
  signature = REXML::Element.new( 'signature' )
  signature.add_text( Format::bin2hex( sig ) )
  @doc.root.delete_element( 'signature' )
  @doc.root.add_element( signature )
end
signature() click to toggle source

Return the signature

# File lib/ec2/amitools/manifestv3.rb, line 295
def signature
  get_element_text('signature')
end
size() click to toggle source

Return the size of the AMI.

# File lib/ec2/amitools/manifestv3.rb, line 252
def size()
  return get_element_text( 'image/size' ).to_i()
end
to_s() click to toggle source

Return the manifest as an XML string.

# File lib/ec2/amitools/manifestv3.rb, line 307
def to_s()
  return @doc.to_s
end
user() click to toggle source
# File lib/ec2/amitools/manifestv3.rb, line 311
def user()
  return get_element_text( 'image/user' )
end
user_encrypted_iv() click to toggle source

The user encrypted initialization vector hex encoded.

# File lib/ec2/amitools/manifestv3.rb, line 209
def user_encrypted_iv()
  return get_element_text( 'image/user_encrypted_iv' )
end
user_encrypted_key() click to toggle source

The user encrypted key hex encoded.

# File lib/ec2/amitools/manifestv3.rb, line 199
def user_encrypted_key()
  return get_element_text( 'image/user_encrypted_key' )
end
version() click to toggle source
# File lib/ec2/amitools/manifestv3.rb, line 315
def version()
  return get_element_text( 'version' ).to_i
end

Private Instance Methods

get_element_text( xpath ) click to toggle source
# File lib/ec2/amitools/manifestv3.rb, line 321
def get_element_text( xpath )
  element = REXML::XPath.first( @doc.root, xpath )
  unless element
    raise "invalid AMI manifest, #{xpath} element not present"
  end
  unless element.text
    raise "invalid AMI manifest, #{xpath} element empty"
  end
  return element.text
end