func (node *nodeImpl) getEnrollmentCertificateFromECA(id, pw string) (interface{}, []byte, []byte, error) { // Get a new ECA Client sock, ecaP, err := node.getECAClient() defer sock.Close() // Run the protocol signPriv, err := primitives.NewECDSAKey() if err != nil { node.Errorf("Failed generating ECDSA key [%s].", err.Error()) return nil, nil, nil, err } signPub, err := x509.MarshalPKIXPublicKey(&signPriv.PublicKey) if err != nil { node.Errorf("Failed mashalling ECDSA key [%s].", err.Error()) return nil, nil, nil, err } encPriv, err := primitives.NewECDSAKey() if err != nil { node.Errorf("Failed generating Encryption key [%s].", err.Error()) return nil, nil, nil, err } encPub, err := x509.MarshalPKIXPublicKey(&encPriv.PublicKey) if err != nil { node.Errorf("Failed marshalling Encryption key [%s].", err.Error()) return nil, nil, nil, err } req := &membersrvc.ECertCreateReq{ Ts: ×tamp.Timestamp{Seconds: time.Now().Unix(), Nanos: 0}, Id: &membersrvc.Identity{Id: id}, Tok: &membersrvc.Token{Tok: []byte(pw)}, Sign: &membersrvc.PublicKey{Type: membersrvc.CryptoType_ECDSA, Key: signPub}, Enc: &membersrvc.PublicKey{Type: membersrvc.CryptoType_ECDSA, Key: encPub}, Sig: nil} resp, err := ecaP.CreateCertificatePair(context.Background(), req) if err != nil { node.Errorf("Failed invoking CreateCertficatePair [%s].", err.Error()) return nil, nil, nil, err } if resp.FetchResult != nil && resp.FetchResult.Status != membersrvc.FetchAttrsResult_SUCCESS { node.Warning(resp.FetchResult.Msg) } //out, err := rsa.DecryptPKCS1v15(rand.Reader, encPriv, resp.Tok.Tok) spi := ecies.NewSPI() eciesKey, err := spi.NewPrivateKey(nil, encPriv) if err != nil { node.Errorf("Failed parsing decrypting key [%s].", err.Error()) return nil, nil, nil, err } ecies, err := spi.NewAsymmetricCipherFromPublicKey(eciesKey) if err != nil { node.Errorf("Failed creating asymmetrinc cipher [%s].", err.Error()) return nil, nil, nil, err } out, err := ecies.Process(resp.Tok.Tok) if err != nil { node.Errorf("Failed decrypting toke [%s].", err.Error()) return nil, nil, nil, err } req.Tok.Tok = out req.Sig = nil hash := primitives.NewHash() raw, _ := proto.Marshal(req) hash.Write(raw) r, s, err := ecdsa.Sign(rand.Reader, signPriv, hash.Sum(nil)) if err != nil { node.Errorf("Failed signing [%s].", err.Error()) return nil, nil, nil, err } R, _ := r.MarshalText() S, _ := s.MarshalText() req.Sig = &membersrvc.Signature{Type: membersrvc.CryptoType_ECDSA, R: R, S: S} resp, err = ecaP.CreateCertificatePair(context.Background(), req) if err != nil { node.Errorf("Failed invoking CreateCertificatePair [%s].", err.Error()) return nil, nil, nil, err } // Verify response // Verify cert for signing node.Debugf("Enrollment certificate for signing [% x]", primitives.Hash(resp.Certs.Sign)) x509SignCert, err := primitives.DERToX509Certificate(resp.Certs.Sign) if err != nil { node.Errorf("Failed parsing signing enrollment certificate for signing: [%s]", err) return nil, nil, nil, err } _, err = primitives.GetCriticalExtension(x509SignCert, ECertSubjectRole) if err != nil { node.Errorf("Failed parsing ECertSubjectRole in enrollment certificate for signing: [%s]", err) return nil, nil, nil, err } err = primitives.CheckCertAgainstSKAndRoot(x509SignCert, signPriv, node.ecaCertPool) if err != nil { node.Errorf("Failed checking signing enrollment certificate for signing: [%s]", err) return nil, nil, nil, err } // Verify cert for encrypting node.Debugf("Enrollment certificate for encrypting [% x]", primitives.Hash(resp.Certs.Enc)) x509EncCert, err := primitives.DERToX509Certificate(resp.Certs.Enc) if err != nil { node.Errorf("Failed parsing signing enrollment certificate for encrypting: [%s]", err) return nil, nil, nil, err } _, err = primitives.GetCriticalExtension(x509EncCert, ECertSubjectRole) if err != nil { node.Errorf("Failed parsing ECertSubjectRole in enrollment certificate for encrypting: [%s]", err) return nil, nil, nil, err } err = primitives.CheckCertAgainstSKAndRoot(x509EncCert, encPriv, node.ecaCertPool) if err != nil { node.Errorf("Failed checking signing enrollment certificate for encrypting: [%s]", err) return nil, nil, nil, err } return signPriv, resp.Certs.Sign, resp.Pkchain, nil }
//helper function for multiple tests func enrollUser(user *User) error { ecap := &ECAP{eca} // Phase 1 of the protocol: Generate crypto material signPriv, err := primitives.NewECDSAKey() user.enrollPrivKey = signPriv if err != nil { return err } signPub, err := x509.MarshalPKIXPublicKey(&signPriv.PublicKey) if err != nil { return err } encPriv, err := primitives.NewECDSAKey() if err != nil { return err } encPub, err := x509.MarshalPKIXPublicKey(&encPriv.PublicKey) if err != nil { return err } req := &pb.ECertCreateReq{ Ts: &google_protobuf.Timestamp{Seconds: time.Now().Unix(), Nanos: 0}, Id: &pb.Identity{Id: user.enrollID}, Tok: &pb.Token{Tok: user.enrollPwd}, Sign: &pb.PublicKey{Type: pb.CryptoType_ECDSA, Key: signPub}, Enc: &pb.PublicKey{Type: pb.CryptoType_ECDSA, Key: encPub}, Sig: nil} resp, err := ecap.CreateCertificatePair(context.Background(), req) if err != nil { return err } //Phase 2 of the protocol spi := ecies.NewSPI() eciesKey, err := spi.NewPrivateKey(nil, encPriv) if err != nil { return err } ecies, err := spi.NewAsymmetricCipherFromPublicKey(eciesKey) if err != nil { return err } out, err := ecies.Process(resp.Tok.Tok) if err != nil { return err } req.Tok.Tok = out req.Sig = nil hash := primitives.NewHash() raw, _ := proto.Marshal(req) hash.Write(raw) r, s, err := ecdsa.Sign(rand.Reader, signPriv, hash.Sum(nil)) if err != nil { return err } R, _ := r.MarshalText() S, _ := s.MarshalText() req.Sig = &pb.Signature{Type: pb.CryptoType_ECDSA, R: R, S: S} resp, err = ecap.CreateCertificatePair(context.Background(), req) if err != nil { return err } // Verify we got valid crypto material back x509SignCert, err := primitives.DERToX509Certificate(resp.Certs.Sign) if err != nil { return err } _, err = primitives.GetCriticalExtension(x509SignCert, ECertSubjectRole) if err != nil { return err } x509EncCert, err := primitives.DERToX509Certificate(resp.Certs.Enc) if err != nil { return err } _, err = primitives.GetCriticalExtension(x509EncCert, ECertSubjectRole) if err != nil { return err } return nil }
// CreateCertificatePair requests the creation of a new enrollment certificate pair by the ECA. // func (ecap *ECAP) CreateCertificatePair(ctx context.Context, in *pb.ECertCreateReq) (*pb.ECertCreateResp, error) { Trace.Println("gRPC ECAP:CreateCertificate") // validate token var tok, prev []byte var role, state int var enrollID string id := in.Id.Id err := ecap.eca.readUser(id).Scan(&role, &tok, &state, &prev, &enrollID) if err != nil || !bytes.Equal(tok, in.Tok.Tok) { return nil, errors.New("Identity or token does not match.") } ekey, err := x509.ParsePKIXPublicKey(in.Enc.Key) if err != nil { return nil, err } switch { case state == 0: // initial request, create encryption challenge tok = []byte(randomString(12)) _, err = ecap.eca.db.Exec("UPDATE Users SET token=?, state=?, key=? WHERE id=?", tok, 1, in.Enc.Key, id) if err != nil { Error.Println(err) return nil, err } spi := ecies.NewSPI() eciesKey, err := spi.NewPublicKey(nil, ekey.(*ecdsa.PublicKey)) if err != nil { return nil, err } ecies, err := spi.NewAsymmetricCipherFromPublicKey(eciesKey) if err != nil { return nil, err } out, err := ecies.Process(tok) return &pb.ECertCreateResp{Certs: nil, Chain: nil, Pkchain: nil, Tok: &pb.Token{Tok: out}}, err case state == 1: // ensure that the same encryption key is signed that has been used for the challenge if subtle.ConstantTimeCompare(in.Enc.Key, prev) != 1 { return nil, errors.New("Encryption keys do not match.") } // validate request signature sig := in.Sig in.Sig = nil r, s := big.NewInt(0), big.NewInt(0) r.UnmarshalText(sig.R) s.UnmarshalText(sig.S) if in.Sign.Type != pb.CryptoType_ECDSA { return nil, errors.New("Unsupported (signing) key type.") } skey, err := x509.ParsePKIXPublicKey(in.Sign.Key) if err != nil { return nil, err } hash := primitives.NewHash() raw, _ := proto.Marshal(in) hash.Write(raw) if ecdsa.Verify(skey.(*ecdsa.PublicKey), hash.Sum(nil), r, s) == false { return nil, errors.New("Signature verification failed.") } // create new certificate pair ts := time.Now().Add(-1 * time.Minute).UnixNano() spec := NewDefaultCertificateSpecWithCommonName(id, enrollID, skey.(*ecdsa.PublicKey), x509.KeyUsageDigitalSignature, pkix.Extension{Id: ECertSubjectRole, Critical: true, Value: []byte(strconv.Itoa(ecap.eca.readRole(id)))}) sraw, err := ecap.eca.createCertificateFromSpec(spec, ts, nil) if err != nil { Error.Println(err) return nil, err } spec = NewDefaultCertificateSpecWithCommonName(id, enrollID, ekey.(*ecdsa.PublicKey), x509.KeyUsageDataEncipherment, pkix.Extension{Id: ECertSubjectRole, Critical: true, Value: []byte(strconv.Itoa(ecap.eca.readRole(id)))}) eraw, err := ecap.eca.createCertificateFromSpec(spec, ts, nil) if err != nil { ecap.eca.db.Exec("DELETE FROM Certificates Where id=?", id) Error.Println(err) return nil, err } _, err = ecap.eca.db.Exec("UPDATE Users SET state=? WHERE id=?", 2, id) if err != nil { ecap.eca.db.Exec("DELETE FROM Certificates Where id=?", id) Error.Println(err) return nil, err } var obcECKey []byte if role == int(pb.Role_VALIDATOR) { obcECKey = ecap.eca.obcPriv } else { obcECKey = ecap.eca.obcPub } return &pb.ECertCreateResp{Certs: &pb.CertPair{Sign: sraw, Enc: eraw}, Chain: &pb.Token{Tok: ecap.eca.obcKey}, Pkchain: obcECKey, Tok: nil}, nil } return nil, errors.New("Invalid (=expired) certificate creation token provided.") }