Overview
Comment: | Add preliminary support for package scripts that have a PGP signature instead of a Harpy certificate. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
4335ea0899da7691c16b94b9f35eae23 |
User & Date: | mistachkin on 2016-08-16 21:35:49 |
Other Links: | manifest | tags |
Context
2016-08-16
| ||
23:16 | Add preliminary support for package scripts that are signed using OpenPGP. check-in: d81d61b270 user: mistachkin tags: trunk | |
21:35 | Add preliminary support for package scripts that have a PGP signature instead of a Harpy certificate. check-in: 4335ea0899 user: mistachkin tags: trunk | |
03:10 | Add initial draft of the package downloader tool. check-in: 878f889075 user: mistachkin tags: trunk | |
Changes
Modified client/pkgr.eagle from [a7fc39bbae] to [ebedd45873].
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 | return [string is list $value] } elseif {[catch {llength $value}] == 0} then { return true } else { return false } } proc getLookupVarNamePrefix {} { return ::rpkg_; # TODO: Make non-global? } proc getLookupVarNameSuffix {} { return [appendArgs \ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | return [string is list $value] } elseif {[catch {llength $value}] == 0} then { return true } else { return false } } proc isHarpyCertificate { value } { if {[string length $value] == 0 || [string first [string trim { <Certificate xmlns="https://eagle.to/2011/harpy" }] $value] != -1} then { return true } else { return false } } proc isPgpSignature { value {strict false} } { if {[string length $value] == 0 || [string first [string trim { -----BEGIN PGP SIGNATURE----- }] $value] != -1} then { return true } else { return false } } proc verifyPgpSignature { fileName } { variable pgpCommand if {[isEagle]} then { set fileName [appendArgs \" $fileName \"] return [expr {[catch { eval exec -success Success [subst $pgpCommand]}] == 0 }] } else { return [expr {[catch { eval exec [subst $pgpCommand] 2>@1 }] == 0}] } } proc getLookupVarNamePrefix {} { return ::rpkg_; # TODO: Make non-global? } proc getLookupVarNameSuffix {} { return [appendArgs \ |
︙ | ︙ | |||
293 294 295 296 297 298 299 | # NOTE: If the package script certificate is mising, fail. # if {![info exists metadata(certificate)]} then { error "missing script certificate" } # | > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | # NOTE: If the package script certificate is mising, fail. # if {![info exists metadata(certificate)]} then { error "missing script certificate" } # # NOTE: Figure out the "type" of script certificate we are now dealing # with. # if {[isHarpyCertificate $metadata(certificate)]} then { # # NOTE: Attempt to create a completely unique array variable name to # hold the package metadata in this scripting language as well # as possibly in the other necessary scripting language(s). # set newVarName [appendArgs \ [getLookupVarNamePrefix] metadata_ [getLookupVarNameSuffix]] set newProcName(1) [appendArgs \ [getLookupVarNamePrefix] eagleHasSecurity_ [getLookupVarNameSuffix]] set newProcName(2) [appendArgs \ [getLookupVarNamePrefix] tclMustBeReady_ [getLookupVarNameSuffix]] # # NOTE: Create the Eagle script block that will be used to securely # evaluate a signed package script. This must be evaluated in # Eagle because it uses several plugins only available there. # set script(outer) [string map [list \ %metadata% $newVarName %eagleHasSecurity% $newProcName(1) \ %tclMustBeReady% $newProcName(2)] { try { # # NOTE: If there is no package ifneeded script, there is nothing we # can do here. # if {[string length ${%metadata%(ifNeeded)}] > 0} then { # # NOTE: Save the security state for the interpreter. Then, attempt # to enable it. This will fail if one of the needed plugins # cannot be loaded. # set savedSecurity [{%eagleHasSecurity%}] if {!$savedSecurity} then {source enableSecurity} try { # # NOTE: Figure out temporary file name for the downloaded script # and its associated script certificate. # set fileName(1) [file tempname] set fileName(2) [appendArgs $fileName(1) .harpy] try { # # NOTE: Write the downloaded script to a temporary file. # writeFile $fileName(1) ${%metadata%(ifNeeded)} # # NOTE: Write the downloaded script certificateto a temporary # file. # if {[string length ${%metadata%(certificate)}] > 0} then { writeFile $fileName(2) ${%metadata%(certificate)} } # # NOTE: This seems stupid. Why are we reading the downloaded # script from the temporary file when we already had it # in memory? The reason is that we need to make sure # that the Harpy policy engine has a chance to check the # downloaded script against its associated certificate. # This will raise a script error if the script signature # is missing or invalid. # set script(inner) [interp readorgetscriptfile -- \ "" $fileName(1)] # # 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 explicitly specified, is Eagle. In # the future, this may be changed, e.g. to use the file # extension of the client script. # switch -exact -- ${%metadata%(language)} { "" - Eagle { # # NOTE: The target language is Eagle, which is evaluating # this script. No special handling is needed here. # return [uplevel #0 $script(inner)] } Tcl { # # NOTE: The target language is Tcl; therefore, a bit of # special handling is needed here. # {%tclMustBeReady%}; return [tcl eval [tcl master] [list \ uplevel #0 $script(inner)]] } default { error "unsupported language" } } } finally { # # NOTE: Delete any temporary files that we created during the # signed script evaluation. # if {[string length $fileName(2)] > 0 && \ [file exists $fileName(2)]} then { catch {file delete $fileName(2)} unset -nocomplain fileName(2) } if {[string length $fileName(1)] > 0 && \ [file exists $fileName(1)]} then { catch {file delete $fileName(1)} unset -nocomplain fileName(1) } } } finally { # # NOTE: Restore the saved security state for the interpreter. # if {!$savedSecurity} then {source disableSecurity} unset -nocomplain savedSecurity } } } finally { rename {%tclMustBeReady%} "" rename {%eagleHasSecurity%} "" unset -nocomplain {%metadata%} } }] # # NOTE: Copy the package metadata into the fresh array variable, # if necessary, marshalling it from native Tcl to Eagle. # if {[isEagle]} then { array set $newVarName [array get metadata] proc $newProcName(1) {} [info body [appendArgs \ [namespace current] ::eagleHasSecurity]] proc $newProcName(2) {} [info body [appendArgs \ [namespace current] ::tclMustBeReady]] return [eval $script(outer)] } else { eagleMustBeReady eagle [list array set $newVarName [array get metadata]] eagle [list proc $newProcName(1) {} [info body [appendArgs \ [namespace current] ::eagleHasSecurity]]] eagle [list proc $newProcName(2) {} [info body [appendArgs \ [namespace current] ::tclMustBeReady]]] return [eagle $script(outer)] } } elseif {[isPgpSignature $metadata(certificate)]} then { error "not yet implemented" } else { error "unsupported script certificate" } } proc setupPackageUnknownHandler {} { variable autoHook variable autoLoadTcl variable autoRequireGaruda |
︙ | ︙ | |||
633 634 635 636 637 638 639 640 641 642 643 644 645 646 | # loaded from the Tcl language? # variable autoRequireGaruda; # DEFAULT: true if {![info exists autoRequireGaruda]} then { set autoRequireGaruda true } } proc main { package version } { # # NOTE: Issue the lookup request to the remote package repository. # set data [getLookupData \ | > > > > > > > > > > | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 | # loaded from the Tcl language? # variable autoRequireGaruda; # DEFAULT: true if {![info exists autoRequireGaruda]} then { set autoRequireGaruda true } # # NOTE: The command to use when verifying OpenPGP signatures for the # downloaded package scripts. # variable pgpCommand; # DEFAULT: gpg2 --verify {${fileName}} if {![info exists pgpCommand]} then { set pgpCommand {gpg2 --verify {${fileName}}} } } proc main { package version } { # # NOTE: Issue the lookup request to the remote package repository. # set data [getLookupData \ |
︙ | ︙ |
Modified client/pkgr.eagle.harpy from [a971336653] to [391949f600].
︙ | ︙ | |||
17 18 19 20 21 22 23 | THE ASSOCIATED SOFTWARE MAY NOT WORK PROPERLY IF THIS FILE IS ALTERED. --> <Certificate xmlns="https://eagle.to/2011/harpy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Protocol>None</Protocol> <Vendor>Mistachkin Systems</Vendor> | | | | | | | | | | | | | | | | | | | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | THE ASSOCIATED SOFTWARE MAY NOT WORK PROPERLY IF THIS FILE IS ALTERED. --> <Certificate xmlns="https://eagle.to/2011/harpy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Protocol>None</Protocol> <Vendor>Mistachkin Systems</Vendor> <Id>ed124b1a-4d17-4891-8565-cca6d319e05d</Id> <HashAlgorithm>SHA512</HashAlgorithm> <EntityType>Script</EntityType> <TimeStamp>2016-08-16T21:34:49.8991719Z</TimeStamp> <Duration>-1.00:00:00</Duration> <Key>0x2c322765603b5278</Key> <Signature> HfIXyk05Fdr92bC3TsiyVrc9wkALImMYIkeLLlxqdwqq/E+MFw86KoxVioFP/RQXiaaHoThtK9YO CWy96n9d3fZXDBvq7o1eneSYH+QECU0CGB8ffzQs4fHoDECjrTg85crQeyzfQUYG/OkI5N9OipBf +i6QyTnomS1NSNogtS5uhcxeg3hGk8MClsxsgRVrPDNkQdM9jIqI0TklIy4bE1Z9OmG8kfjpewXP S/3FZqQugahida3tfCmWICQez1sSvSSx04k+s7Duf3lHCUvCBy7DbNwow2hlWhAIwdmx6eZtK/h9 lQgbAGIJERDengtiA2wVXxAvZ4RpdRfnMt5HfLlZKOaWxTDdPQq5J8eDI2iHZYogXZfKewFTMnl6 r+4tyDCt1t5DLUS+leBltmKH7VMQKWcncVSc0D/PFT9DsKtOndvwntpIWbx4aLPk//zLS4kqu7oX ajUeTSms2KK5cAy4JQl27i85XakzmWz65772rcxmEjdujVGG33GYxJ+DsSYmEUgV77qOocz/ASe4 pG7Ke+CvCpPHyb//M8y3D+XskpMZZbXKbKYKRdCUaEC7BzxeSXfYAqJLcJgq6v+u66vI+rtZeDrD lQ4RMjCuqJkAFaszObTQ6cyn9KX71vWLzjDYKPNQXyWUhavqRH7FZw/HvyRs2c++KuKqNhv0ABlp ZKeyZeRQ5xiyb2fiufszqxnKwhaqDXvvnFkJaJ0bxP3/bDq8Sw64ZfvJkICZ5Bh7McHQo40K02c3 JnyNBdyaeUiRkSpE2JtZvpPL1NkXbzTijW7+ecV+0IffurmenmZl8HZVlWBeJsYwHw8IFRRQVM9i 9TPcD4Tuy52aD5RitnuVGW0ac7MY3gLkmpDV16sO0h2JXl+w7UsarLGHUYeg5UXgP/bneoeNrH7R kjLvXvGbxUxHg/lrvIm9SOdoCY0mLgI+V9ww5trhy3TwqMmDdtLM4n6aXjqaxsuefyMmxvgemP0q GL5XyvRcIS/xACWe8zgottX2iy8qwHrwvaUFnQ0Srak48t4h1o6+7zEnpcvxeFJLv8jRdQofqq/A Gsp4A9nKQzEn4lfIGp5+yedKtZtvN68EMIedBnPAJkWCmZ9H8NnWlsVvvSlMqhZv51a+MkcVNvEa ga0Y/ctcaAsUU4iuAr7DL4X9cLjRY7ghcZMlHjFziPZ4FJUJXwSAkSzbDKG3Tyzpwhfl75ZvCuwe odPSsWZoLDGBxpdJUWAqleUf8+IeOnoonp5bGvEHyXO2RclW2uW57tppEMOHWrbbchd/hC20u/T1 A/TZPqz246Tow9w98aVp+rvI9Vhp7rhfMi6FGeYyiYYhkD14OJDlL7wIZAx2IDtGZOK7hw+SCQ== </Signature> </Certificate> |