blob: 9ef816b248fcba3e811c506963aa91cb2ac4cfe5 [file] [log] [blame]
// +build android
package security
import (
"crypto/ecdsa"
"runtime"
"veyron/jni/runtimes/google/util"
"veyron2/security"
)
// #cgo LDFLAGS: -ljniwrapper
// #include "jni_wrapper.h"
import "C"
func newPublicID(env *C.JNIEnv, jPublicID C.jobject) *publicID {
// We cannot cache Java environments as they are only valid in the current
// thread. We can, however, cache the Java VM and obtain an environment
// from it in whatever thread happens to be running at the time.
var jVM *C.JavaVM
if status := C.GetJavaVM(env, &jVM); status != 0 {
panic("couldn't get Java VM from the (Java) environment")
}
// Reference Java public id; it will be de-referenced when the go public id
// created below is garbage-collected (through the finalizer callback we
// setup just below).
jPublicID = C.NewGlobalRef(env, jPublicID)
id := &publicID{
jVM: jVM,
jPublicID: jPublicID,
}
runtime.SetFinalizer(id, func(id *publicID) {
var env *C.JNIEnv
C.AttachCurrentThread(id.jVM, &env, nil)
defer C.DetachCurrentThread(id.jVM)
C.DeleteGlobalRef(env, id.jPublicID)
})
return id
}
type publicID struct {
jVM *C.JavaVM
jPublicID C.jobject
}
func (id *publicID) Names() []string {
envPtr, freeFunc := util.GetEnv(id.jVM)
env := (*C.JNIEnv)(envPtr)
defer freeFunc()
return util.CallStringArrayMethodOrCatch(env, id.jPublicID, "names", nil)
}
func (id *publicID) PublicKey() *ecdsa.PublicKey {
envPtr, freeFunc := util.GetEnv(id.jVM)
env := (*C.JNIEnv)(envPtr)
defer freeFunc()
publicKeySign := util.ClassSign("java.security.interfaces.ECPublicKey")
jPublicKey := C.jobject(util.CallObjectMethodOrCatch(env, id.jPublicID, "publicKey", nil, publicKeySign))
// Get the encoded version of the public key.
encoded := util.CallByteArrayMethodOrCatch(env, jPublicKey, "getEncoded", nil)
key, err := parsePKIXPublicKey(encoded)
if err != nil {
panic("couldn't parse Java ECDSA public key: " + err.Error())
}
return key
}
func (id *publicID) Authorize(context security.Context) (security.PublicID, error) {
envPtr, freeFunc := util.GetEnv(id.jVM)
env := (*C.JNIEnv)(envPtr)
defer freeFunc()
jContext := newJavaContext(env, context)
contextSign := util.ClassSign("com.veyron2.security.Context")
publicIDSign := util.ClassSign("com.veyron2.security.PublicID")
jPublicID, err := util.CallObjectMethod(env, id.jPublicID, "authorize", []util.Sign{contextSign}, publicIDSign, jContext)
if err != nil {
return nil, err
}
return newPublicID(env, C.jobject(jPublicID)), nil
}
func (id *publicID) ThirdPartyCaveats() []security.ServiceCaveat {
envPtr, freeFunc := util.GetEnv(id.jVM)
env := (*C.JNIEnv)(envPtr)
defer freeFunc()
serviceCaveatSign := util.ClassSign("com.veyron2.security.ServiceCaveat")
jServiceCaveats := util.CallObjectArrayMethodOrCatch(env, id.jPublicID, "thirdPartyCaveats", nil, util.ArraySign(serviceCaveatSign))
sCaveats := make([]security.ServiceCaveat, len(jServiceCaveats))
for i, jcaveat := range jServiceCaveats {
sCaveats[i] = security.ServiceCaveat{
Service: security.BlessingPattern(util.JStringField(env, C.jobject(jcaveat), "service")),
Caveat: newCaveat(env, C.jobject(jcaveat)),
}
}
return sCaveats
}