1
/*******************************************************************************
2
*Copyright (c) 2009 Eucalyptus Systems, Inc.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation, only version 3 of the License.
9
* This file is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* You should have received a copy of the GNU General Public License along
15
* with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Please contact Eucalyptus Systems, Inc., 130 Castilian
18
* Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
19
* if you need additional information or have any questions.
21
* This file may incorporate work covered under the following copyright and
24
* Software License Agreement (BSD License)
26
* Copyright (c) 2008, Regents of the University of California
27
* All rights reserved.
29
* Redistribution and use of this software in source and binary forms, with
30
* or without modification, are permitted provided that the following
33
* Redistributions of source code must retain the above copyright notice,
34
* this list of conditions and the following disclaimer.
36
* Redistributions in binary form must reproduce the above copyright
37
* notice, this list of conditions and the following disclaimer in the
38
* documentation and/or other materials provided with the distribution.
40
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
41
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
43
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
44
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
51
* THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
52
* LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
53
* SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
54
* IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
55
* BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
56
* THE REGENTS’ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
57
* OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
58
* WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
59
* ANY SUCH LICENSES OR RIGHTS.
60
*******************************************************************************/
61
package com.eucalyptus.images.util;
63
import java.io.ByteArrayInputStream;
64
import java.security.PrivateKey;
65
import java.util.List;
67
import javax.crypto.Cipher;
68
import javax.xml.parsers.DocumentBuilder;
69
import javax.xml.parsers.DocumentBuilderFactory;
71
import org.w3c.dom.Document;
73
import com.eucalyptus.auth.CredentialProvider;
74
import com.eucalyptus.auth.NoSuchUserException;
75
import com.eucalyptus.auth.SystemCredentialProvider;
76
import com.eucalyptus.auth.X509Cert;
77
import com.eucalyptus.auth.util.Hashes;
78
import com.eucalyptus.bootstrap.Component;
79
import com.eucalyptus.util.EucalyptusCloudException;
80
import com.eucalyptus.ws.client.RemoteDispatcher;
81
import com.eucalyptus.ws.client.ServiceDispatcher;
82
import com.google.common.collect.Lists;
84
import edu.ucsb.eucalyptus.cloud.entities.ImageInfo;
85
import edu.ucsb.eucalyptus.cloud.ws.ImageManager;
86
import edu.ucsb.eucalyptus.msgs.CacheImageType;
87
import edu.ucsb.eucalyptus.msgs.CheckImageType;
88
import edu.ucsb.eucalyptus.msgs.FlushCachedImageType;
89
import edu.ucsb.eucalyptus.msgs.GetBucketAccessControlPolicyResponseType;
90
import edu.ucsb.eucalyptus.msgs.GetBucketAccessControlPolicyType;
91
import edu.ucsb.eucalyptus.msgs.GetObjectResponseType;
92
import edu.ucsb.eucalyptus.msgs.GetObjectType;
93
import edu.ucsb.eucalyptus.msgs.RegisterImageType;
94
import edu.ucsb.eucalyptus.util.Admin;
95
import edu.ucsb.eucalyptus.util.XMLParser;
97
public class WalrusUtil {
99
public static void checkValid( ImageInfo imgInfo ) {
100
String[] parts = imgInfo.getImageLocation().split( "/" );
101
CheckImageType check = new CheckImageType();
102
check.setUserId( imgInfo.getImageOwnerId( ) );
103
check.setBucket( parts[ 0 ] );
104
check.setKey( parts[ 1 ] );
105
RemoteDispatcher.lookupSingle( Component.walrus ).dispatch( check );
108
public static void triggerCaching( ImageInfo imgInfo ) {
109
String[] parts = imgInfo.getImageLocation().split( "/" );
110
CacheImageType cache = new CacheImageType();
111
cache.setUserId( imgInfo.getImageOwnerId( ) );
112
cache.setBucket( parts[ 0 ] );
113
cache.setKey( parts[ 1 ] );
114
RemoteDispatcher.lookupSingle( Component.walrus ).dispatch( cache );
117
public static void invalidate( ImageInfo imgInfo ) {
118
String[] parts = imgInfo.getImageLocation().split( "/" );
119
imgInfo.setImageState( "deregistered" );
121
RemoteDispatcher.lookupSingle( Component.walrus ).dispatch( new FlushCachedImageType( parts[ 0 ], parts[ 1 ] ) );
122
} catch ( Exception e ) {}
125
public static Document getManifestData( String userId, String bucketName, String objectName ) throws EucalyptusCloudException {
126
GetObjectResponseType reply = null;
128
GetObjectType msg = new GetObjectType( bucketName, objectName, true, false, true );
129
msg.setUserId( userId );
131
reply = ( GetObjectResponseType ) RemoteDispatcher.lookupSingle( Component.walrus ).send( msg );
133
catch ( Exception e ) {
134
throw new EucalyptusCloudException( "Failed to read manifest file: " + bucketName + "/" + objectName, e );
137
Document inputSource = null;
139
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
140
inputSource = builder.parse( new ByteArrayInputStream( Hashes.base64decode(reply.getBase64Data() ).getBytes() ));
142
catch ( Exception e ) {
143
throw new EucalyptusCloudException( "Failed to read manifest file: " + bucketName + "/" + objectName, e );
148
public static GetBucketAccessControlPolicyResponseType getBucketAcl( RegisterImageType request, String[] imagePathParts ) throws EucalyptusCloudException {
149
GetBucketAccessControlPolicyType getBukkitInfo = Admin.makeMsg( GetBucketAccessControlPolicyType.class, request );
150
if(getBukkitInfo != null) {
151
getBukkitInfo.setBucket( imagePathParts[ 0 ] );
152
GetBucketAccessControlPolicyResponseType reply = ( GetBucketAccessControlPolicyResponseType ) RemoteDispatcher.lookupSingle( Component.walrus ).send( getBukkitInfo );
158
public static void verifyManifestIntegrity( final ImageInfo imgInfo ) throws EucalyptusCloudException {
159
String[] imagePathParts = imgInfo.getImageLocation().split( "/" );
160
GetObjectResponseType reply = null;
161
GetObjectType msg = new GetObjectType( imagePathParts[ 0 ], imagePathParts[ 1 ], true, false, true );
162
msg.setUserId( Component.eucalyptus.name() );
163
msg.setEffectiveUserId( Component.eucalyptus.name() );
165
reply = ( GetObjectResponseType ) ServiceDispatcher.lookupSingle( Component.walrus ).send( msg );
166
} catch ( EucalyptusCloudException e ) {
167
ImageManager.LOG.error( e );
168
ImageManager.LOG.debug( e, e );
169
throw new EucalyptusCloudException( "Invalid manifest reference: " + imgInfo.getImageLocation(), e );
172
if ( reply == null || reply.getBase64Data() == null ) throw new EucalyptusCloudException( "Invalid manifest reference: " + imgInfo.getImageLocation() );
173
XMLParser parser = new XMLParser( Hashes.base64decode(reply.getBase64Data()) );
174
String encryptedKey = parser.getValue( "//ec2_encrypted_key" );
175
String encryptedIV = parser.getValue( "//ec2_encrypted_iv" );
176
String signature = parser.getValue( "//signature" );
177
String image = parser.getXML( "image" );
178
String machineConfiguration = parser.getXML( "machine_configuration" );
180
List<String> aliases = Lists.newArrayList();
182
for( X509Cert x : CredentialProvider.getUser( imgInfo.getImageOwnerId( ) ).getCertificates( ) ) {
183
aliases.add( x.getAlias( ) );
185
} catch ( NoSuchUserException e ) {
186
throw new EucalyptusCloudException( "Invalid Manifest: Failed to verify signature because of missing (deleted?) user certificate.", e );
188
boolean found = false;
189
for ( String alias : aliases )
190
found |= ImageUtil.verifyManifestSignature( signature, alias, machineConfiguration + image );
191
if ( !found ) throw new EucalyptusCloudException( "Invalid Manifest: Failed to verify signature." );
194
PrivateKey pk = SystemCredentialProvider.getCredentialProvider(Component.eucalyptus).getPrivateKey();
195
Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
196
cipher.init( Cipher.DECRYPT_MODE, pk );
197
cipher.doFinal( Hashes.hexToBytes( encryptedKey ) );
198
cipher.doFinal( Hashes.hexToBytes( encryptedIV ) );
199
} catch ( Exception ex ) {
200
throw new EucalyptusCloudException( "Invalid Manifest: Failed to recover keys.", ex );