95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
-
+
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
|
#
# NOTE: This procedure returns non-zero if the specified string value
# looks like a Harpy (script) certificate. The value argument
# is the string to check.
#
# <public>
proc isHarpyCertificate { value } {
if {[string length $value] == 0 || [string first [string trim {
if {[string length $value] == 0 || ([string first [string trim {
<?xml version="1.0" encoding="utf-8"?>
}] $value] == 0 && [string first [string trim {
<Certificate xmlns="https://eagle.to/2011/harpy"
}] $value] != -1} then {
}] $value] != -1)} then {
return true
} else {
return false
}
}
#
# NOTE: This procedure returns non-zero if the specified string value
# looks like a PGP signature. The value argument is the string
# to check.
# looks like an OpenPGP signature. The value argument is the
# string to check.
#
# <public>
proc isPgpSignature { value } {
if {[string length $value] == 0 || [string first [string trim {
-----BEGIN PGP SIGNATURE-----
}] $value] != -1} then {
}] $value] == 0} then {
return true
} else {
return false
}
}
#
# NOTE: This procedure returns the fully qualified name of the directory
# where temporary files should be written. The envVarName argument
# is an optional extra environment variable to check (first).
#
proc getFileTempDirectory { {envVarName ""} } {
global env
if {[string length $envVarName] > 0 && \
[info exists env($envVarName)]} then {
return $env($envVarName)
} elseif {[info exists env(TEMP)]} then {
return $env(TEMP)
} elseif {[info exists env(TMP)]} then {
return $env(TMP)
} else {
error [appendArgs \
"please set " $envVarName \
" (via environment) to temporary directory"]
}
}
#
# NOTE: This procedure returns a unique temporary file name. A script
# error is raised if this task cannot be accomplished. There are
# no arguments.
#
proc getFileTempName {} {
if {[isEagle]} then {
return [file tempname]
} else {
global env
if {[info exists env(PKGR_TEMP)]} then {
set directory $env(PKGD_TEMP)
} elseif {[info exists env(TEMP)]} then {
set directory $env(TEMP)
} elseif {[info exists env(TMP)]} then {
set directory $env(TMP)
set directory [getFileTempDirectory PKGR_TEMP]
} else {
error "please set PKGR_TEMP (via environment) to temporary directory"
}
set counter [expr {[pid] ^ int(rand() * 0xFFFF)}]
while {1} {
set fileNameOnly [format tcl%04X.tmp $counter]
set fileName [file join $directory $fileNameOnly]
if {![file exists $fileName]} then {
return $fileName
}
incr counter
}
}
}
#
# NOTE: This procedure attempts to verify the PGP signature contained in
# the specified (named) file. Non-zero is only returned if the PGP
# signature is verified successfully. A script error should not be
# raised by this procedure. The fileName argument must be the fully
# qualified path and file name of the PGP signature file to verify.
# NOTE: This procedure attempts to verify the OpenPGP signature contained
# in the specified (named) file. Non-zero is only returned if the
# OpenPGP signature is verified successfully. A script error should
# not be raised by this procedure. The fileName argument must be
# the fully qualified path and file name of the OpenPGP signature
# file to verify.
#
# <public>
proc verifyPgpSignature { fileName } {
variable pgpCommand
if {[isEagle]} then {
set fileName [appendArgs \" $fileName \"]
|
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
|
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
|
-
-
+
+
|
return false
}
#
# NOTE: This procedure uses the package lookup metadata. If the package
# script is properly signed, an attempt will be made to evaluate it
# in the target language. If the script was signed using PGP, then
# a conforming implementation of the OpenPGP specification (e.g.
# in the target language. If the script was signed using OpenPGP,
# then a conforming implementation of the OpenPGP specification (e.g.
# gpg2) must be installed locally. If the script was signed using
# Harpy then Garuda, Eagle, and Harpy must be installed locally.
# This procedure is designed to work for both native Tcl and Eagle
# packages. Additionally, it is designed to work when evaluated
# using either native Tcl or Eagle; however, it is up to the package
# script itself to either add the package or provide the package to
# the language(s) supported by that package. The varName argument
|
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
|
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
|
-
+
-
+
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
|
#
# NOTE: If there is no package script, there is nothing we
# can do here.
#
if {[string length $metadata(script)] > 0} then {
#
# NOTE: Figure out temporary file name for the downloaded script
# and its associated PGP signature.
# and its associated OpenPGP signature.
#
set fileName(1) [getFileTempName]
set fileName(2) [appendArgs $fileName(1) .asc]
#
# NOTE: Write downloaded script to a temporary file.
#
writeFile $fileName(1) $metadata(script)
#
# NOTE: Write downloaded script PGP signature a temporary file.
# NOTE: Write downloaded script OpenPGP signature a temporary file.
#
if {[string length $metadata(certificate)] > 0} then {
writeFile $fileName(2) $metadata(certificate)
}
#
# NOTE: Attempt to verify the PGP signature for the package script.
# NOTE: Attempt to verify the OpenPGP signature for the package
# script.
#
if {[verifyPgpSignature $fileName(2)]} then {
#
# NOTE: Delete the temporary files that we created for the PGP
# signature verification.
# NOTE: Delete the temporary files that we created for the
# OpenPGP signature verification.
#
eval $script(cleanup)
} else {
#
# NOTE: Delete the temporary files that we created for the PGP
# signature verification.
# NOTE: Delete the temporary files that we created for the
# OpenPGP signature verification.
#
eval $script(cleanup)
#
# NOTE: PGP signature verification failed. Raise an error and
# do not proceed with evaluating the package script.
# NOTE: OpenPGP signature verification failed. Raise an error
# and do not proceed with evaluating the package script.
#
error "bad PGP signature"
}
#
# NOTE: The PGP signature was verified; use the downloaded package
# script verbatim.
# NOTE: The OpenPGP signature was verified; use the downloaded
# package script verbatim.
#
set script(inner) $metadata(script)
#
# NOTE: Determine the target language for the package script, which
# may or may not be the language that is currently evaluating
# this script (Eagle). The default language, when one was not
|