package main // Pemverify ver.0.6 // coded by Kenar import ( . "fmt" "os" "encoding/pem" "crypto/rsa" "crypto/sha1" "crypto/sha256" "crypto/x509" "math/big" "reflect" ) var usage = "usage: pemverify cert.pem" func Error(s ... interface{}){ Fprintln(os.Stderr,s[:]...) os.Exit(1) } // Expected usage: // b := Err(os.ReadFile(args[0])) // I want to improve so that original type is returned // don't use yet func Err(arg interface{}, err error) interface{} { if err != nil { Error(err) } return arg } func check(err error) { if err != nil { Error(err) } } func verify(certp *x509.Certificate, pubkeyp *rsa.PublicKey){ cert := *certp t := *pubkeyp // pubkey for signing C := cert.RawTBSCertificate var H []byte switch(cert.SignatureAlgorithm){ case x509.SHA256WithRSA: // func Sum256(data []byte) [Size]byte h := sha256.Sum256(C) H = h[:] // OK but sha256.Sum256(C)[:] is NG. why? Println("SHA256WithRSA") case x509.SHA1WithRSA: h := sha1.Sum(C) H = h[:] Println("SHA1WithRSA") default: Error("unsupported Signature Algorith") } // the above coding is clumsy // but I donn't have a better solution Printf("H=%x\n", string(H)) sig := cert.Signature Printf("C=%x\n",string(C)) // TBSSertificate //Printf("sig=%0*x\n",size,string(sig)) N := t.N // $GOROOT/src/math/big/int.go // func (x *Int) BitLen() int // want hexstring size of N n := N.BitLen() size := 1+ (n-1)/4 // assuming n > 0 E := big.NewInt(int64(t.E)) Printf("N=%0*x\n", size, N) Printf("E=%x\n", E) S := big.NewInt(0) S.SetBytes(sig) Printf("S=%0*x\n",size,S) // signature D := big.NewInt(0) D.Exp(S,E,N) // pow(S,E,N) in python notation Printf("D=%0*x\n",size,D) } const ( max = 10 ) func main() { var pb [max]*pem.Block var k int args := os.Args[1:] if len(args) != 1 { Error(usage) } bs,err := os.ReadFile(args[0]) check(err) for k=0; len(bs) > 0 ; k++ { pb[k],bs = pem.Decode(bs) } for k=0; pb[k] != nil; k++ { if k != 0 { Println() } if pb[k+1] == nil { // self-signed ? // we need to look up SubjectKeyId and SubjectKeyId cert,err := x509.ParseCertificate(pb[k].Bytes) check(err) if reflect.DeepEqual(cert.SubjectKeyId, cert.AuthorityKeyId) { // self-signed pk := cert.PublicKey.(*rsa.PublicKey) verify(cert, pk) break } msg := Sprintf("Need publick key for\n %v\n KeyId=%x", cert.Issuer, cert.AuthorityKeyId) Error(msg) } cert0,err := x509.ParseCertificate(pb[k].Bytes) check(err) cert1,err := x509.ParseCertificate(pb[k+1].Bytes) pk1 := cert1.PublicKey.(*rsa.PublicKey) verify(cert0, pk1) } }