This commit is contained in:
Ben Toews 2017-11-29 12:36:08 -07:00
Родитель d0d0da8687
Коммит 5abdd89a0b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E9C423BE17EFEE70
5 изменённых файлов: 100 добавлений и 41 удалений

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

@ -0,0 +1,37 @@
package main
import (
"fmt"
"strings"
)
func commandListKeys() int {
idents, err := store.Identities()
if err != nil {
panic(err)
}
for _, ident := range idents {
defer ident.Close()
}
for j, ident := range idents {
cert, err := ident.Certificate()
if err != nil {
panic(err)
}
if j > 0 {
fmt.Println("————————————————————")
}
fmt.Println(" ID:", certHexFingerprint(cert))
fmt.Println(" S/N:", cert.SerialNumber.Text(16))
fmt.Println("Algorithm:", cert.SignatureAlgorithm.String())
fmt.Println(" Validity:", cert.NotBefore.String(), "-", cert.NotAfter.String())
fmt.Println(" Issuer:", rdnSequenceString(cert.Issuer.ToRDNSequence()))
fmt.Println(" Subject:", rdnSequenceString(cert.Subject.ToRDNSequence()))
fmt.Println(" Emails:", strings.Join(certEmails(cert), ", "))
}
return 0
}

35
main.go
Просмотреть файл

@ -10,16 +10,17 @@ import (
var (
// Action flags
helpFlag = getopt.BoolLong("help", 'h', "print this help message")
signFlag = getopt.BoolLong("sign", 's', "make a signature")
verifyFlag = getopt.BoolLong("verify", 0, "verify a signature")
helpFlag = getopt.BoolLong("help", 'h', "print this help message")
signFlag = getopt.BoolLong("sign", 's', "make a signature")
verifyFlag = getopt.BoolLong("verify", 0, "verify a signature")
listKeysFlag = getopt.BoolLong("list-keys", 0, "show keys")
// Option flags
localUserOpt = getopt.StringLong("local-user", 'u', "", "use USER-ID to sign", "USER-ID")
detachSignFlag = getopt.BoolLong("detach-sign", 'b', "make a detached signature")
armorFlag = getopt.BoolLong("armor", 'a', "create ascii armored output")
statusFdOpt = getopt.IntLong("status-fd", 0, -1, "Write special status strings to the file descriptor n.", "n")
keyFormatOpt = getopt.EnumLong("keyid-format", 0, []string{"short", "0xshort", "long", "0xlong"}, "short", "Select how to display key IDs.", "{short|0xshort|long|0xlong}")
keyFormatOpt = getopt.EnumLong("keyid-format", 0, []string{"long"}, "long", "Select how to display key IDs.", "{long}")
fileArgs []string
store certstore.Store
@ -41,23 +42,23 @@ func main() {
status := 1
if *helpFlag {
if *signFlag || *verifyFlag {
fmt.Println("specify --help, --sign, or --verify")
if *signFlag || *verifyFlag || *listKeysFlag {
fmt.Println("specify --help, --sign, --verify, or --list-keys")
} else {
getopt.Usage()
status = 0
}
} else if *signFlag {
if *helpFlag || *verifyFlag {
fmt.Println("specify --help, --sign, or --verify")
if *helpFlag || *verifyFlag || *listKeysFlag {
fmt.Println("specify --help, --sign, --verify, or --list-keys")
} else if len(*localUserOpt) == 0 {
fmt.Println("specify a USER-ID to sign with")
} else {
status = commandSign()
}
} else if *verifyFlag {
if *helpFlag || *signFlag {
fmt.Println("specify --help, --sign, or --verify")
if *helpFlag || *signFlag || *listKeysFlag {
fmt.Println("specify --help, --sign, --verify, or --list-keys")
} else if len(*localUserOpt) > 0 {
fmt.Println("local-user cannot be specified for verification")
} else if *detachSignFlag {
@ -67,8 +68,20 @@ func main() {
} else {
status = commandVerify()
}
} else if *listKeysFlag {
if *helpFlag || *signFlag || *verifyFlag {
fmt.Println("specify --help, --sign, --verify, or --list-keys")
} else if len(*localUserOpt) > 0 {
fmt.Println("local-user cannot be specified for list-keys")
} else if *detachSignFlag {
fmt.Println("detach-sign cannot be specified for list-keys")
} else if *armorFlag {
fmt.Println("armor cannot be specified for list-keys")
} else {
status = commandListKeys()
}
} else {
fmt.Println("specify --help, --sign, or --verify")
fmt.Println("specify --help, --sign, --verify, or --list-keys")
}
os.Exit(status)

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

@ -40,27 +40,28 @@ import (
// 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",
"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",
"1.2.840.113549.1.9.1": "EMAIL",
}
// 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 {
func rdnSequenceString(r pkix.RDNSequence) string {
s := ""
for i := 0; i < len(r); i++ {
rdn := r[len(r)-1-i]
if i > 0 {
s += ","
s += ", "
}
for j, tv := range rdn {
if j > 0 {

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

@ -190,14 +190,14 @@ func emitSigCreated(cert *x509.Certificate, isDetached bool) {
}
func emitGoodSig(certs []*x509.Certificate) {
subj := RDNSequenceString(certs[0].Subject.ToRDNSequence())
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())
subj := rdnSequenceString(certs[0].Subject.ToRDNSequence())
fpr := certHexFingerprint(certs[0])
sBadSig.emitf("%s %s", fpr, subj)

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

@ -6,6 +6,7 @@ import (
"crypto/x509"
"encoding/asn1"
"encoding/hex"
"regexp"
"strings"
)
@ -75,27 +76,34 @@ var (
// certHasEmail checks if a certificate contains the given email address in its
// subject (CN/emailAddress) or SAN fields.
func certHasEmail(cert *x509.Certificate, email string) bool {
if len(email) == 0 {
return false
}
// Check SAN
for _, other := range cert.EmailAddresses {
for _, other := range certEmails(cert) {
if other == email {
return true
}
}
// Check CN and emailAddress fields in cert subject.
for _, name := range cert.Subject.Names {
if !name.Type.Equal(oidEmailAddress) && !name.Type.Equal(oidCommonName) {
continue
}
if other, isStr := name.Value.(string); isStr && other == email {
return true
}
}
return false
}
// borrowed from http://emailregex.com/
var emailRegexp = regexp.MustCompile(`(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)`)
// certEmails extracts email addresses from a certificate's subject
// (CN/emailAddress) and SAN extensions.
func certEmails(cert *x509.Certificate) []string {
// From SAN
emails := cert.EmailAddresses
// From CN and emailAddress fields in subject.
for _, name := range cert.Subject.Names {
if !name.Type.Equal(oidEmailAddress) && !name.Type.Equal(oidCommonName) {
continue
}
if email, isStr := name.Value.(string); isStr && emailRegexp.MatchString(email) {
emails = append(emails, email)
}
}
return emails
}