emit statuses during verification

This commit is contained in:
Ben Toews 2017-11-28 17:25:14 -07:00
Родитель 6778dab005
Коммит 8d6b7a642f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E9C423BE17EFEE70
4 изменённых файлов: 209 добавлений и 55 удалений

Просмотреть файл

@ -30,6 +30,11 @@ func commandSign() int {
return 1
}
// Git is looking for "\n[GNUPG:] SIG_CREATED ", meaning we need to print a
// line before SIG_CREATED. BEGING_SIGNING seems appropraite. GPG emits this,
// though GPGSM does not.
sBeginSigning.emit()
chain, err := userIdent.CertificateChain()
if err != nil {
panic(err)
@ -55,7 +60,6 @@ func commandSign() int {
panic(err)
}
// SIG_CREATED
emitSigCreated(chain[0], *detachSignFlag)
if *armorFlag {

Просмотреть файл

@ -13,6 +13,8 @@ import (
)
func commandVerify() int {
sNewSig.emit()
if len(fileArgs) < 2 {
return verifyAttached()
}
@ -56,12 +58,25 @@ func verifyAttached() int {
}
// Verify signature
if _, err = sd.Verify(rootsPool()); err != nil {
certs, err := sd.Verify(rootsPool())
if err != nil {
if len(certs) > 0 {
emitBadSig(certs)
} else {
// TODO: We're ommitting a bunch of arguments here.
sErrSig.emit()
}
fmt.Printf("Sinature verification failed: %s\n", err.Error())
return 1
}
fmt.Println("Signature verified")
emitGoodSig(certs)
// TODO: Maybe split up signature checking and certificate checking so we can
// output something more meaningful.
emitTrustFully()
return 0
}
@ -107,12 +122,26 @@ func verifyDetached() int {
if _, err = io.Copy(buf, f); err != nil {
panic(err)
}
if _, err = sd.VerifyDetached(buf.Bytes(), rootsPool()); err != nil {
certs, err := sd.VerifyDetached(buf.Bytes(), rootsPool())
if err != nil {
if len(certs) > 0 {
emitBadSig(certs)
} else {
// TODO: We're ommitting a bunch of arguments here.
sErrSig.emit()
}
fmt.Printf("Sinature verification failed: %s\n", err.Error())
return 1
}
fmt.Println("Signature verified")
emitGoodSig(certs)
// TODO: Maybe split up signature checking and certificate checking so we can
// output something more meaningful.
emitTrustFully()
return 0
}

111
rdn_sequence_string.go Normal file
Просмотреть файл

@ -0,0 +1,111 @@
package main
import (
"crypto/x509/pkix"
"encoding/asn1"
"encoding/hex"
"fmt"
)
// The following was copied from the crypto/openpgpg/packet package.
// The original license can be found at https://git.io/vbUMQ
//
// Copyright (c) 2009 The Go Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var attributeTypeNames = map[string]string{
"2.5.4.6": "C",
"2.5.4.10": "O",
"2.5.4.11": "OU",
"2.5.4.3": "CN",
"2.5.4.5": "SERIALNUMBER",
"2.5.4.7": "L",
"2.5.4.8": "ST",
"2.5.4.9": "STREET",
"2.5.4.17": "POSTALCODE",
}
// The orignal code can be found at https://git.io/vbUMS
//
// String implements the fmt.Stringer interface. It loosely follows the
// string conversion rules for Distinguished Names from RFC 2253.
func RDNSequenceString(r pkix.RDNSequence) string {
s := ""
for i := 0; i < len(r); i++ {
rdn := r[len(r)-1-i]
if i > 0 {
s += ","
}
for j, tv := range rdn {
if j > 0 {
s += "+"
}
oidString := tv.Type.String()
typeName, ok := attributeTypeNames[oidString]
if !ok {
derBytes, err := asn1.Marshal(tv.Value)
if err == nil {
s += oidString + "=#" + hex.EncodeToString(derBytes)
continue // No value escaping necessary.
}
typeName = oidString
}
valueString := fmt.Sprint(tv.Value)
escaped := make([]rune, 0, len(valueString))
for k, c := range valueString {
escape := false
switch c {
case ',', '+', '"', '\\', '<', '>', ';':
escape = true
case ' ':
escape = k == 0 || k == len(valueString)-1
case '#':
escape = k == 0
}
if escape {
escaped = append(escaped, '\\', c)
} else {
escaped = append(escaped, c)
}
}
s += typeName + "=" + string(escaped)
}
}
return s
}

110
status.go
Просмотреть файл

@ -19,6 +19,10 @@ import (
type status string
const (
// BEGIN_SIGNING
// Mark the start of the actual signing process. This may be used as an
// indication that all requested secret keys are ready for use.
sBeginSigning status = "BEGING_SIGNING"
// SIG_CREATED <type> <pk_algo> <hash_algo> <class> <timestamp> <keyfpr>
// A signature has been created using these parameters.
@ -54,44 +58,27 @@ const (
// also be available for OpenPGP.
sGoodSig status = "GOODSIG"
// VALIDSIG <args>
// BADSIG <long_keyid_or_fpr> <username>
// The signature with the keyid has not been verified okay. The username is
// the primary one encoded in UTF-8 and %XX escaped. The fingerprint may be
// used instead of the long keyid if it is available. This is the case with
// CMS and might eventually also be available for OpenPGP.
sBadSig status = "BADSIG"
// ERRSIG <keyid> <pkalgo> <hashalgo> <sig_class> <time> <rc>
//
// The args are:
// It was not possible to check the signature. This may be caused by a
// missing public key or an unsupported algorithm. A RC of 4 indicates
// unknown algorithm, a 9 indicates a missing public key. The other fields
// give more information about this signature. sig_class is a 2 byte hex-
// value. The fingerprint may be used instead of the keyid if it is
// available. This is the case with gpgsm and might eventually also be
// available for OpenPGP.
//
// - <fingerprint_in_hex>
// - <sig_creation_date>
// - <sig-timestamp>
// - <expire-timestamp>
// - <sig-version>
// - <reserved>
// - <pubkey-algo>
// - <hash-algo>
// - <sig-class>
// - [ <primary-key-fpr> ]
//
// This status indicates that the signature is cryptographically
// valid. This is similar to GOODSIG, EXPSIG, EXPKEYSIG, or REVKEYSIG
// (depending on the date and the state of the signature and signing
// key) but has the fingerprint as the argument. Multiple status
// lines (VALIDSIG and the other appropriate *SIG status) are emitted
// for a valid signature. All arguments here are on one long line.
// sig-timestamp is the signature creation time in seconds after the
// epoch. expire-timestamp is the signature expiration time in
// seconds after the epoch (zero means "does not
// expire"). sig-version, pubkey-algo, hash-algo, and sig-class (a
// 2-byte hex value) are all straight from the signature packet.
// PRIMARY-KEY-FPR is the fingerprint of the primary key or identical
// to the first argument. This is useful to get back to the primary
// key without running gpg again for this purpose.
//
// The primary-key-fpr parameter is used for OpenPGP and not
// available for CMS signatures. The sig-version as well as the sig
// class is not defined for CMS and currently set to 0 and 00.
//
// Note, that *-TIMESTAMP may either be a number of seconds since
// Epoch or an ISO 8601 string which can be detected by the presence
// of the letter 'T'.
sValidSig status = "VALIDSIG"
// Note, that TIME may either be the number of seconds since Epoch or an ISO
// 8601 string. The latter can be detected by the presence of the letter
// T.
sErrSig status = "ERRSIG"
// TRUST_
// These are several similar status codes:
@ -119,18 +106,7 @@ const (
//
// Note that the term =TRUST_= in the status names is used for
// historic reasons; we now speak of validity.
sTrustUndefined status = "TRUST_UNDEFINED"
sTrustNever status = "TRUST_NEVER"
sTrustMarginal status = "TRUST_MARGINAL"
sTrustFully status = "TRUST_FULLY"
sTrustUltimate status = "TRUST_ULTIMATE"
// VERIFICATION_COMPLIANCE_MODE <flags>
// Indicates that the current signature verification operation is in
// compliance with the given set of modes. "flags" is a space
// separated list of numerical flags, see "Field 18 - Compliance
// flags" above.
sVerificationComplianceMode = "VERIFICATION_COMPLIANCE_MODE"
sTrustFully status = "TRUST_FULLY"
)
var (
@ -138,7 +114,7 @@ var (
statusFile *os.File
)
func (s status) emit(format string, args ...interface{}) {
func (s status) emitf(format string, args ...interface{}) {
setupStatus.Do(func() {
if *statusFdOpt > 0 {
// TODO: debugging output if this fails
@ -156,6 +132,22 @@ func (s status) emit(format string, args ...interface{}) {
fmt.Fprintf(statusFile, " "+format+"\n", args...)
}
func (s status) emit() {
setupStatus.Do(func() {
if *statusFdOpt > 0 {
// TODO: debugging output if this fails
statusFile = os.NewFile(uintptr(*statusFdOpt), "status")
}
})
if statusFile == nil {
return
}
const prefix = "[GNUPG:] "
statusFile.WriteString(prefix + string(s) + "\n")
}
func emitSigCreated(cert *x509.Certificate, isDetached bool) {
// SIG_CREATED arguments
var (
@ -194,5 +186,23 @@ func emitSigCreated(cert *x509.Certificate, isDetached bool) {
now = time.Now().Unix()
fpr = certHexFingerprint(cert)
sSigCreated.emit("%s %d %d %02x %d %s", sigType, pkAlgo, hashAlgo, sigClass, now, fpr)
sSigCreated.emitf("%s %d %d %02x %d %s", sigType, pkAlgo, hashAlgo, sigClass, now, fpr)
}
func emitGoodSig(certs []*x509.Certificate) {
subj := RDNSequenceString(certs[0].Subject.ToRDNSequence())
fpr := certHexFingerprint(certs[0])
sGoodSig.emitf("%s %s", fpr, subj)
}
func emitBadSig(certs []*x509.Certificate) {
subj := RDNSequenceString(certs[0].Subject.ToRDNSequence())
fpr := certHexFingerprint(certs[0])
sBadSig.emitf("%s %s", fpr, subj)
}
func emitTrustFully() {
sTrustFully.emitf("0 shell")
}