Index: README.md
==================================================================
--- README.md
+++ README.md
@@ -16,28 +16,29 @@
     /opt/appfs/hostname
     	Fetches: http://hostname/appfs/index
     	Contains CSV file: hash,hashMethod,<certificateInDERFormatInHex>,<PKCS#1v1.5-signature-inDERFormatInHex>
 	                   \-------------/
                                   ^- Signed data
-    	Fetches: http://hostname/appfs/sha1/<hash>
-    	Contains CSV file: package,version,os,cpuArch,sha1,isLatest
+    	Fetches: http://hostname/appfs/<hashMethod>/<hash>
+    	Contains CSV file: package,version,os,cpuArch,packageManifestHash,isLatest
 
     /opt/appfs/hostname/package/os-cpuArch/version
-    /opt/appfs/hostname/sha1/
-    	Fetches: http://hostname/appfs/sha1/<sha1>
+    /opt/appfs/hostname/<hashMethod>/
+    	Fetches: http://hostname/appfs/<hashMethod>/<packageManifestHash>
     	Contains CSV file:
     		type,time,extraData,name
     		type == directory; extraData = (null)
     		type == symlink; extraData = source
-    		type == file; extraData = size,perms,sha1
+    		type == file; extraData = size,perms,fileHash
 
-    /opt/appfs/hostname/{sha1,package/os-cpuArch/version}/file
-    	Fetches: http://hostname/appfs/sha1/<sha1>
+    /opt/appfs/hostname/{packageManifestHash,package/os-cpuArch/version}/file
+    	Fetches: http://hostname/appfs/<hashMethod>/<fileHash>
 
 Database
 --------
-    packages(hostname, sha1, package, version, os, cpuArch, isLatest, haveManifest)
-    files(package_sha1, type, time, source, size, perms, file_sha1, file_name, file_directory)
+    sites(hostname, hashMethod, lastUpdate, ttl)
+    packages(hostname, packageManifestHash, package, version, os, cpuArch, isLatest, haveManifest)
+    files(packageManifestHash, type, time, source, size, perms, fileHash, file_name, file_directory)
 
 Resources
 ---------
 http://appfs.rkeene.org/

Index: appfsd.tcl
==================================================================
--- appfsd.tcl
+++ appfsd.tcl
@@ -42,17 +42,19 @@
 	proc get_homedir {} {
 		return [::appfsd::get_homedir]
 	}
 
 	# User-replacable function to update permissions
-	proc change_perms {file sha1 perms} {
+	proc change_perms {file hash perms {hashMethod "sha1"}} {
 		if {[info exists ::appfs::user::add_perms($file)]} {
 			append perms $::appfs::user::add_perms($file)
 		}
 
-		if {[info exists ::appfs::user::add_perms($sha1)]} {
-			append perms $::appfs::user::add_perms($sha1)
+		if {[info exists ::appfs::user::add_perms([list $hashMethod $hash])]} {
+			append perms $::appfs::user::add_perms([list $hashMethod $hash])
+		} elseif {$hashMethod eq "sha1" && [info exists ::appfs::user::add_perms($hash)]} {
+			append perms $::appfs::user::add_perms($hash)
 		}
 
 		return $perms
 	}
 
@@ -166,31 +168,27 @@
 
 
 	proc _isHash {value} {
 		set value [string tolower $value]
 
-		if {[string length $value] != 40} {
-			return false
-		}
-
 		if {![regexp {^[0-9a-f]*$} $value]} {
 			return false
 		}
 
 		return true
 	}
 
-	proc _verifySignatureAndCertificate {hostname certificate signature hash} {
+	proc _verifySignatureAndCertificate {hostname certificate signature hash hashmethod} {
 		set certificate [binary format "H*" $certificate]
 		set signature   [binary format "H*" $signature]
 
 		set certificate [::pki::x509::parse_cert $certificate]
 
 		array set certificate_arr $certificate
 		set certificate_cn [::pki::x509::_dn_to_cn $certificate_arr(subject)]
 
-		if {![::pki::verify $signature "$hash,sha1" $certificate]} {
+		if {![::pki::verify $signature "$hash,$hashmethod" $certificate]} {
 			return false
 		}
 
 		if {[string tolower $certificate_cn] != [string tolower $hostname]} {
 			return false
@@ -310,18 +308,18 @@
 
 			::appfs::db timeout 30000
 		}
 
 		# Create tables
-		db eval {CREATE TABLE IF NOT EXISTS sites(hostname PRIMARY KEY, lastUpdate, ttl);}
-		db eval {CREATE TABLE IF NOT EXISTS packages(hostname, sha1, package, version, os, cpuArch, isLatest, haveManifest);}
-		db eval {CREATE TABLE IF NOT EXISTS files(package_sha1, type, time, source, size, perms, file_sha1, file_name, file_directory);}
+		db eval {CREATE TABLE IF NOT EXISTS sites(hostname PRIMARY KEY, hashMethod, lastUpdate, ttl);}
+		db eval {CREATE TABLE IF NOT EXISTS packages(hostname, packageManifestHash, package, version, os, cpuArch, isLatest, haveManifest);}
+		db eval {CREATE TABLE IF NOT EXISTS files(packageManifestHash, hashMethod, type, time, source, size, perms, fileHash, file_name, file_directory);}
 
 		# Create indexes
 		db eval {CREATE INDEX IF NOT EXISTS sites_index ON sites (hostname);}
-		db eval {CREATE INDEX IF NOT EXISTS packages_index ON packages (hostname, sha1, package, version, os, cpuArch);}
-		db eval {CREATE INDEX IF NOT EXISTS files_index ON files (package_sha1, file_name, file_directory);}
+		db eval {CREATE INDEX IF NOT EXISTS packages_index ON packages (hostname, packageManifestHash, package, version, os, cpuArch);}
+		db eval {CREATE INDEX IF NOT EXISTS files_index ON files (packageManifestHash, file_name, file_directory);}
 	}
 
 	proc download {hostname hash {method sha1}} {
 		set url [::appfs::user::construct_url $hostname $hash $method]
 		set file [_cachefile $url $hash $method]
@@ -376,15 +374,15 @@
 
 		if {![_isHash $indexhash]} {
 			return -code error "Invalid hash: $indexhash"
 		}
 
-		if {![_verifySignatureAndCertificate $hostname $indexhashcert $indexhashsig $indexhash]} {
+		if {![_verifySignatureAndCertificate $hostname $indexhashcert $indexhashsig $indexhash $indexhashmethod]} {
 			return -code error "Invalid signature or certificate from $hostname"
 		}
 
-		set file [download $hostname $indexhash]
+		set file [download $hostname $indexhash $indexhashmethod]
 		catch {
 			set fd [open $file]
 		}
 
 		if {![info exists fd]} {
@@ -417,11 +415,11 @@
 				set pkgInfo(package)  [lindex $work 0]
 				set pkgInfo(version)  [lindex $work 1]
 				set pkgInfo(os)       [_normalizeOS [lindex $work 2]]
 				set pkgInfo(cpuArch)  [_normalizeCPU [lindex $work 3]]
 				set pkgInfo(hash)     [string tolower [lindex $work 4]]
-				set pkgInfo(hash_type) "sha1"
+				set pkgInfo(hash_type) $indexhashmethod
 				set pkgInfo(isLatest) [expr {!![lindex $work 5]}]
 			}]} {
 				continue
 			}
 
@@ -430,20 +428,20 @@
 			}
 
 			lappend curr_packages $pkgInfo(hash)
 
 			# Do not do any additional work if we already have this package
-			set existing_packages [db eval {SELECT package FROM packages WHERE hostname = $hostname AND sha1 = $pkgInfo(hash);}]
+			set existing_packages [db eval {SELECT package FROM packages WHERE hostname = $hostname AND packageManifestHash = $pkgInfo(hash);}]
 			if {[lsearch -exact $existing_packages $pkgInfo(package)] != -1} {
 				continue
 			}
 
 			if {$pkgInfo(isLatest)} {
 				db eval {UPDATE packages SET isLatest = 0 WHERE hostname = $hostname AND package = $pkgInfo(package) AND os = $pkgInfo(os) AND cpuArch = $pkgInfo(cpuArch);}
 			}
 
-			db eval {INSERT INTO packages (hostname, sha1, package, version, os, cpuArch, isLatest, haveManifest) VALUES ($hostname, $pkgInfo(hash), $pkgInfo(package), $pkgInfo(version), $pkgInfo(os), $pkgInfo(cpuArch), $pkgInfo(isLatest), 0);}
+			db eval {INSERT INTO packages (hostname, packageManifestHash, package, version, os, cpuArch, isLatest, haveManifest) VALUES ($hostname, $pkgInfo(hash), $pkgInfo(package), $pkgInfo(version), $pkgInfo(os), $pkgInfo(cpuArch), $pkgInfo(isLatest), 0);}
 		}
 
 		# Look for packages that have been deleted
 		set found_packages [db eval {SELECT sha1 FROM packages WHERE hostname = $hostname;}]
 		foreach package $found_packages {
@@ -453,32 +451,33 @@
 		foreach package $curr_packages {
 			unset -nocomplain found_packages_arr($package)
 		}
 
 		foreach package [array names found_packages_arr] {
-			db eval {DELETE FROM packages WHERE hostname = $hostname AND sha1 = $package;}
+			db eval {DELETE FROM packages WHERE hostname = $hostname AND packageManifestHash = $package;}
 		}
 
-		db eval {INSERT OR REPLACE INTO sites (hostname, lastUpdate, ttl) VALUES ($hostname, $now, $::appfs::ttl);}
+		db eval {INSERT OR REPLACE INTO sites (hostname, hashMethod, lastUpdate, ttl) VALUES ($hostname, $indexhashmethod, $now, $::appfs::ttl);}
 
 		appfsd::get_path_info_cache_flush
 
 		return COMPLETE
 	}
 
-	proc getpkgmanifest {hostname package_sha1} {
-		set haveManifest [db onecolumn {SELECT haveManifest FROM packages WHERE sha1 = $package_sha1 LIMIT 1;}]
+	proc getpkgmanifest {hostname packageManifestHash} {
+		set haveManifest [db onecolumn {SELECT haveManifest FROM packages WHERE packageManifestHash = $packageManifestHash LIMIT 1;}]
+		set siteHashMethod [db onecolumn {SELECT hashMethod FROM sites WHERE hostname = $hostname LIMIT 1;}
 
 		if {$haveManifest == "1"} {
 			return COMPLETE
 		}
 
-		if {![_isHash $package_sha1]} {
+		if {![_isHash $packageManifestHash]} {
 			return FAIL
 		}
 
-		set file [download $hostname $package_sha1]
+		set file [download $hostname $packageManifestHash $siteHashMethod]
 
 		catch {
 			set fd [open $file]
 		}