Jar 檔案數字簽名
JAR 檔案可以用 jarsigner
工具或者直接通過 java.security
API 簽名。一個簽名的 JAR 檔案與原來的 JAR 檔案完全相同,只是更新了它的 manifest,並在 META-INF 目錄中增加了兩個檔案,一個簽名檔案和一個簽名塊檔案。
JAR 檔案是用一個儲存在 Keystore 資料庫中的證書籤名的。儲存在 keystore 中的證書有密碼保護,必須向 jarsigner
工具提供這個密碼才能對 JAR 檔案簽名。
JAR 的每一位簽名者都由在 JAR 檔案的 META-INF 目錄中的一個具有 .SF 副檔名的簽名檔案表示。這個檔案的格式類似於 manifest 檔案 -- 一組 RFC-822 頭。如下所示,它的組成包括一個主要部分,它包括了由簽名者提供的資訊、但是不特別針對任何特定的 JAR 檔案項,還有一系列的單獨的項,這些項也必須包含在 menifest 檔案中。在驗證一個簽名的 JAR 時,將簽名檔案的摘要值與對 JAR 檔案中的相應項計算的摘要值進行比較。
一個數字簽名是.SF 簽名檔案的已簽名版本。數字簽名檔案是二進位制檔案,並且與 .SF 檔案有相同的檔名,但是副檔名不同。根據數字簽名的型別 -- RSA、DSA 或者 PGP -- 以及用於簽名 JAR 的證書型別而有不同的副檔名。
要簽名一個 JAR 檔案,必須首先有一個私鑰。私鑰及其相關的公鑰證書儲存在名為 keystores
的、有密碼保護的資料庫中。JDK 包含建立和修改 keystores 的工具。keystore 中的每一個金鑰都可以用一個別名標識,它通常是擁有這個金鑰的簽名者的名字。
所有 keystore 項(金鑰和信任的證書項)都是用唯一別名訪問的。別名是在用 keytool -genkey
命令生成金鑰對(公鑰和私鑰)並在 keystore 中新增項時指定的。之後的 keytool
命令必須使用同樣的別名引用這一項。
例如,要用別名“james”生成一個新的公鑰/私鑰對並將公鑰包裝到自簽名的證書中,要使用下述命令:
這個命令序列指定了一個初始密碼“jamespass”,後續的命令在訪問 keystore “jamesKeyStore”中與別名“james”相關聯的私鑰時,就需要這個密碼。如果 keystore“jamesKeyStore”不存在,則 keytool
會自動建立它。
jarsigner
工具使用 keystore 生成或者驗證 JAR 檔案的數字簽名。
假設像上述例子那樣建立了 keystore “jamesKeyStore”,並且它包含一個別名為“james”的金鑰,可以用下面的命令簽名一個 JAR 檔案:
這個命令用密碼“jamesKeyStorePass”從名為“jamesKeyStore”的 keystore 中提出別名為“james”、密碼為“jamespass”的金鑰,並對 Sample.jar 檔案簽名、建立一個簽名的 JAR -- SSample.jar。
jarsigner
工具還可以驗證一個簽名的 JAR 檔案,這種操作比簽名 JAR 檔案要簡單得多,只需執行以下命令:
如果簽名的 JAR 檔案沒有被篡改過,那麼 jarsigner
工具就會告訴您 JAR 通過驗證了。否則,它會丟擲一個 SecurityException
, 表明哪些檔案沒有通過驗證。
還可以用 java.util.jar
和 java.security
API 以程式設計方式簽名 JAR(有關細節參閱 參考資料)。也可以使用像 Netscape Object Signing Tool 這樣的工具。
將已簽名的Jar包清理,重新簽名
1. resign.sh script (strips key, adds key, add index)#!/bin/sh# $Id: resign.sh,v 1.3 2002/07/02 13:57:32 mvw Exp $
# This script resigns the jars
# (remove old signature, add new signature)
# settings for present foo server
JDK=/usr/java/j2sdk1.4.0
KEYSTORE=../../Frontend/webstart/key/fooKeystore
../files.sh
for i in $unsigned_files
do
echo "---"
echo "unpacking $i .."
TMP=tmp-$i
mkdir$TMP
cd $TMP
unzip -q ../$i
chmod-R u+rwx *
find .-type f | xargs chmod u-x
echo "changing META-INF stuff .."
cd META-INF
rm -f *.SF
rm -f *.DSA
# this will determine the line number of the first blank line in MANIFEST.MF
# (a blank line here is anything that has no letter/number)
CUT=`egrep -nv '^.*[a-z|A-Z|0-9]+.*$' MANIFEST.MF|sed s/://|head -1|tr -d ""`
if [ -z "$CUT" ];
then
echo "no cut detected";
else
echo "cutting MANIFEST.MF at line $CUT .."&&
head -$CUT MANIFEST.MF >m.mf &&
rm -f MANIFEST.MF &&
mv m.mf MANIFEST.MF &&
cat MANIFEST.MF;
fi
echo "repacking $i .."
cd ..
rm -f ../$i
zip -q9r ../$i.
cd ..
rm -rf $TMP
echo "signing $i .."
$JDK/bin/jarsigner -keystore $KEYSTORE-storepass foopassword $i fookeyname
echo "verifying the signatures of $i .."
$JDK/bin/jarsigner -verify $i
echo indexing $i..
$JDK/bin/jar -i $i
done
2. files.sh (a list of files to treat)
# $Id: files.sh,v 1.1 2002/05/07 16:35:18 mvw Exp $
# Files list
# watch out for
# - the double quotes,
# - the trailing space inside the quoted string,
# - the backslash immediatly following the closing quote
unsigned_files=
"foo1.jar "
"foo2.jar "
"foo3.jar "
"foo-help.jar "
[code]