Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0356f462 authored by Jeff Tinker's avatar Jeff Tinker Committed by Android Git Automerger
Browse files

am 53c90cf9: am 6dc8063d: am 433a0633: Merge "Support CAST V2 Authentication...

am 53c90cf9: am 6dc8063d: am 433a0633: Merge "Support CAST V2 Authentication in MediaDrm" into klp-modular-dev

* commit '53c90cf9':
  Support CAST V2 Authentication in MediaDrm
parents b67c41d2 53c90cf9
Loading
Loading
Loading
Loading
+147 −6
Original line number Original line Diff line number Diff line
@@ -20,11 +20,14 @@ import java.lang.ref.WeakReference;
import java.util.UUID;
import java.util.UUID;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.List;
import android.os.Binder;
import android.os.Debug;
import android.os.Handler;
import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcel;
import android.util.Log;
import android.util.Log;
import android.content.Context;


/**
/**
 * MediaDrm can be used to obtain keys for decrypting protected media streams, in
 * MediaDrm can be used to obtain keys for decrypting protected media streams, in
@@ -100,6 +103,20 @@ public final class MediaDrm {


    private long mNativeContext;
    private long mNativeContext;


    /**
     * Specify no certificate type
     *
     * @hide - not part of the public API at this time
     */
    public static final int CERTIFICATE_TYPE_NONE = 0;

    /**
     * Specify X.509 certificate type
     *
     * @hide - not part of the public API at this time
     */
    public static final int CERTIFICATE_TYPE_X509 = 1;

    /**
    /**
     * Query if the given scheme identified by its UUID is supported on
     * Query if the given scheme identified by its UUID is supported on
     * this device.
     * this device.
@@ -316,6 +333,9 @@ public final class MediaDrm {
     * Contains the opaque data an app uses to request keys from a license server
     * Contains the opaque data an app uses to request keys from a license server
     */
     */
    public final static class KeyRequest {
    public final static class KeyRequest {
        private byte[] mData;
        private String mDefaultUrl;

        KeyRequest() {}
        KeyRequest() {}


        /**
        /**
@@ -329,9 +349,6 @@ public final class MediaDrm {
         * server URL from other sources.
         * server URL from other sources.
         */
         */
        public String getDefaultUrl() { return mDefaultUrl; }
        public String getDefaultUrl() { return mDefaultUrl; }

        private byte[] mData;
        private String mDefaultUrl;
    };
    };


    /**
    /**
@@ -456,7 +473,12 @@ public final class MediaDrm {
     * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
     * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
     * request to is returned in ProvisionRequest.defaultUrl.
     * request to is returned in ProvisionRequest.defaultUrl.
     */
     */
    public native ProvisionRequest getProvisionRequest();
    public ProvisionRequest getProvisionRequest() {
        return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, "");
    }

    private native ProvisionRequest getProvisionRequestNative(int certType,
                                                              String certAuthority);


    /**
    /**
     * After a provision response is received by the app, it is provided to the DRM
     * After a provision response is received by the app, it is provided to the DRM
@@ -468,7 +490,12 @@ public final class MediaDrm {
     * @throws DeniedByServerException if the response indicates that the
     * @throws DeniedByServerException if the response indicates that the
     * server rejected the request
     * server rejected the request
     */
     */
    public native void provideProvisionResponse(byte[] response)
    public void provideProvisionResponse(byte[] response)
        throws DeniedByServerException {
        provideProvisionResponseNative(response);
    }

    private native Certificate provideProvisionResponseNative(byte[] response)
        throws DeniedByServerException;
        throws DeniedByServerException;


    /**
    /**
@@ -683,6 +710,120 @@ public final class MediaDrm {
        return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
        return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
    }
    }


    /**
     * Contains the opaque data an app uses to request a certificate from a provisioning
     * server
     *
     * @hide - not part of the public API at this time
     */
    public final static class CertificateRequest {
        private byte[] mData;
        private String mDefaultUrl;

        CertificateRequest(byte[] data, String defaultUrl) {
            mData = data;
            mDefaultUrl = defaultUrl;
        }

        /**
         * Get the opaque message data
         */
        public byte[] getData() { return mData; }

        /**
         * Get the default URL to use when sending the certificate request
         * message to a server, if known. The app may prefer to use a different
         * certificate server URL obtained from other sources.
         */
        public String getDefaultUrl() { return mDefaultUrl; }
    }

    /**
     * Generate a certificate request, specifying the certificate type
     * and authority. The response received should be passed to
     * provideCertificateResponse.
     *
     * @param certType Specifies the certificate type.
     *
     * @param certAuthority is passed to the certificate server to specify
     * the chain of authority.
     *
     * @hide - not part of the public API at this time
     */
    public CertificateRequest getCertificateRequest(int certType,
                                                    String certAuthority)
    {
        ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority);
        return new CertificateRequest(provisionRequest.getData(),
                                      provisionRequest.getDefaultUrl());
    }

    /**
     * Contains the wrapped private key and public certificate data associated
     * with a certificate.
     *
     * @hide - not part of the public API at this time
     */
    public final static class Certificate {
        Certificate() {}

        /**
         * Get the wrapped private key data
         */
        public byte[] getWrappedPrivateKey() { return mWrappedKey; }

        /**
         * Get the PEM-encoded certificate chain
         */
        public byte[] getContent() { return mCertificateData; }

        private byte[] mWrappedKey;
        private byte[] mCertificateData;
    }


    /**
     * Process a response from the certificate server.  The response
     * is obtained from an HTTP Post to the url provided by getCertificateRequest.
     * <p>
     * The public X509 certificate chain and wrapped private key are returned
     * in the returned Certificate objec.  The certificate chain is in PEM format.
     * The wrapped private key should be stored in application private
     * storage, and used when invoking the signRSA method.
     *
     * @param response the opaque certificate response byte array to provide to the
     * DRM engine plugin.
     *
     * @throws DeniedByServerException if the response indicates that the
     * server rejected the request
     *
     * @hide - not part of the public API at this time
     */
    public Certificate provideCertificateResponse(byte[] response)
        throws DeniedByServerException {
        return provideProvisionResponseNative(response);
    }

    private static final native byte[] signRSANative(MediaDrm drm, byte[] sessionId,
                                                     String algorithm, byte[] wrappedKey,
                                                     byte[] message);

    /**
     * Sign data using an RSA key
     *
     * @param context the app context
     * @param sessionId a sessionId obtained from openSession on the MediaDrm object
     * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
     * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
     * from provideCertificateResponse
     * @param message the data for which a signature is to be computed
     *
     * @hide - not part of the public API at this time
     */
    public byte[] signRSA(Context context, byte[] sessionId, String algorithm, byte[] wrappedKey, byte[] message) {
        return signRSANative(this, sessionId, algorithm, wrappedKey, message);
    }

    @Override
    @Override
    protected void finalize() {
    protected void finalize() {
        native_finalize();
        native_finalize();
+109 −17
Original line number Original line Diff line number Diff line
@@ -100,6 +100,16 @@ struct KeyTypes {
    jint kKeyTypeRelease;
    jint kKeyTypeRelease;
} gKeyTypes;
} gKeyTypes;


struct CertificateTypes {
    jint kCertificateTypeNone;
    jint kCertificateTypeX509;
} gCertificateTypes;

struct CertificateFields {
    jfieldID wrappedPrivateKey;
    jfieldID certificateData;
};

struct fields_t {
struct fields_t {
    jfieldID context;
    jfieldID context;
    jmethodID post_event;
    jmethodID post_event;
@@ -110,6 +120,11 @@ struct fields_t {
    SetFields set;
    SetFields set;
    IteratorFields iterator;
    IteratorFields iterator;
    EntryFields entry;
    EntryFields entry;
    CertificateFields certificate;
    jclass certificateClassId;
    jclass hashmapClassId;
    jclass arraylistClassId;
    jclass stringClassId;
};
};


static fields_t gFields;
static fields_t gFields;
@@ -406,8 +421,7 @@ static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
*/
*/


static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
    jclass clazz;
    jclass clazz = gFields.stringClassId;
    FIND_CLASS(clazz, "java/lang/String");
    KeyedVector<String8, String8> keyedVector;
    KeyedVector<String8, String8> keyedVector;


    jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
    jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
@@ -450,8 +464,7 @@ static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &
}
}


static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
    jclass clazz;
    jclass clazz = gFields.hashmapClassId;
    FIND_CLASS(clazz, "java/util/HashMap");
    jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
    jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
    for (size_t i = 0; i < map.size(); ++i) {
    for (size_t i = 0; i < map.size(); ++i) {
        jstring jkey = env->NewStringUTF(map.keyAt(i).string());
        jstring jkey = env->NewStringUTF(map.keyAt(i).string());
@@ -465,8 +478,7 @@ static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8>


static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
                                                   List<Vector<uint8_t> > list) {
                                                   List<Vector<uint8_t> > list) {
    jclass clazz;
    jclass clazz = gFields.arraylistClassId;
    FIND_CLASS(clazz, "java/util/ArrayList");
    jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
    jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
    List<Vector<uint8_t> >::iterator iter = list.begin();
    List<Vector<uint8_t> >::iterator iter = list.begin();
    while (iter != list.end()) {
    while (iter != list.end()) {
@@ -542,6 +554,11 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
    gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
    gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);


    GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
    gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
    GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
    gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);

    FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
    FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
    GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
    GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
    GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
    GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
@@ -550,6 +567,11 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
    GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
    GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
    GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
    GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");


    FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
    GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
    GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
    gFields.certificateClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));

    FIND_CLASS(clazz, "java/util/ArrayList");
    FIND_CLASS(clazz, "java/util/ArrayList");
    GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
    GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
    GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
    GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
@@ -571,6 +593,15 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
    FIND_CLASS(clazz, "java/util/Map$Entry");
    FIND_CLASS(clazz, "java/util/Map$Entry");
    GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
    GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
    GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
    GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");

    FIND_CLASS(clazz, "java/util/HashMap");
    gFields.hashmapClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));

    FIND_CLASS(clazz, "java/lang/String");
    gFields.stringClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));

    FIND_CLASS(clazz, "java/util/ArrayList");
    gFields.arraylistClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
}
}


static void android_media_MediaDrm_native_setup(
static void android_media_MediaDrm_native_setup(
@@ -826,8 +857,8 @@ static jobject android_media_MediaDrm_queryKeyStatus(
    return KeyedVectorToHashMap(env, infoMap);
    return KeyedVectorToHashMap(env, infoMap);
}
}


static jobject android_media_MediaDrm_getProvisionRequest(
static jobject android_media_MediaDrm_getProvisionRequestNative(
    JNIEnv *env, jobject thiz) {
    JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
    sp<IDrm> drm = GetDrm(env, thiz);
    sp<IDrm> drm = GetDrm(env, thiz);


    if (drm == NULL) {
    if (drm == NULL) {
@@ -839,7 +870,17 @@ static jobject android_media_MediaDrm_getProvisionRequest(
    Vector<uint8_t> request;
    Vector<uint8_t> request;
    String8 defaultUrl;
    String8 defaultUrl;


    status_t err = drm->getProvisionRequest(request, defaultUrl);
    String8 certType;
    if (jcertType == gCertificateTypes.kCertificateTypeX509) {
        certType = "X.509";
    } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
        certType = "none";
    } else {
        certType = "invalid";
    }

    String8 certAuthority = JStringToString8(env, jcertAuthority);
    status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);


    if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
    if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
        return NULL;
        return NULL;
@@ -863,27 +904,43 @@ static jobject android_media_MediaDrm_getProvisionRequest(
    return provisionObj;
    return provisionObj;
}
}


static void android_media_MediaDrm_provideProvisionResponse(
static jobject android_media_MediaDrm_provideProvisionResponseNative(
    JNIEnv *env, jobject thiz, jbyteArray jresponse) {
    JNIEnv *env, jobject thiz, jbyteArray jresponse) {
    sp<IDrm> drm = GetDrm(env, thiz);
    sp<IDrm> drm = GetDrm(env, thiz);


    if (drm == NULL) {
    if (drm == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
        jniThrowException(env, "java/lang/IllegalStateException",
                          "MediaDrm obj is null");
                          "MediaDrm obj is null");
        return;
        return NULL;
    }
    }


    if (jresponse == NULL) {
    if (jresponse == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException",
        jniThrowException(env, "java/lang/IllegalArgumentException",
                          "provision response is null");
                          "provision response is null");
        return;
        return NULL;
    }
    }


    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
    Vector<uint8_t> certificate, wrappedKey;

    status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);

    // Fill out return obj
    jclass clazz = gFields.certificateClassId;

    jobject certificateObj = NULL;

    if (clazz && certificate.size() && wrappedKey.size()) {
        certificateObj = env->AllocObject(clazz);
        jbyteArray jcertificate = VectorToJByteArray(env, certificate);
        env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);


    status_t err = drm->provideProvisionResponse(response);
        jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
        env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
    }


    throwExceptionAsNecessary(env, err, "Failed to handle provision response");
    throwExceptionAsNecessary(env, err, "Failed to handle provision response");
    return certificateObj;
}
}


static jobject android_media_MediaDrm_getSecureStops(
static jobject android_media_MediaDrm_getSecureStops(
@@ -1209,6 +1266,38 @@ static jboolean android_media_MediaDrm_verifyNative(
}
}




static jbyteArray android_media_MediaDrm_signRSANative(
    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
    jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {

    sp<IDrm> drm = GetDrm(env, jdrm);

    if (!CheckSession(env, drm, jsessionId)) {
        return NULL;
    }

    if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException",
                          "required argument is null");
        return NULL;
    }

    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
    String8 algorithm = JStringToString8(env, jalgorithm);
    Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
    Vector<uint8_t> signature;

    status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);

    if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
        return NULL;
    }

    return VectorToJByteArray(env, signature);
}


static JNINativeMethod gMethods[] = {
static JNINativeMethod gMethods[] = {
    { "release", "()V", (void *)android_media_MediaDrm_release },
    { "release", "()V", (void *)android_media_MediaDrm_release },
    { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
    { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
@@ -1244,11 +1333,11 @@ static JNINativeMethod gMethods[] = {
    { "queryKeyStatus", "([B)Ljava/util/HashMap;",
    { "queryKeyStatus", "([B)Ljava/util/HashMap;",
      (void *)android_media_MediaDrm_queryKeyStatus },
      (void *)android_media_MediaDrm_queryKeyStatus },


    { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
    { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
      (void *)android_media_MediaDrm_getProvisionRequest },
      (void *)android_media_MediaDrm_getProvisionRequestNative },


    { "provideProvisionResponse", "([B)V",
    { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
      (void *)android_media_MediaDrm_provideProvisionResponse },
      (void *)android_media_MediaDrm_provideProvisionResponseNative },


    { "getSecureStops", "()Ljava/util/List;",
    { "getSecureStops", "()Ljava/util/List;",
      (void *)android_media_MediaDrm_getSecureStops },
      (void *)android_media_MediaDrm_getSecureStops },
@@ -1287,6 +1376,9 @@ static JNINativeMethod gMethods[] = {


    { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
    { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
      (void *)android_media_MediaDrm_verifyNative },
      (void *)android_media_MediaDrm_verifyNative },

    { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
      (void *)android_media_MediaDrm_signRSANative },
};
};


int register_android_media_Drm(JNIEnv *env) {
int register_android_media_Drm(JNIEnv *env) {
+2 −2
Original line number Original line Diff line number Diff line
@@ -15,7 +15,7 @@
#
#
LOCAL_PATH := $(call my-dir)
LOCAL_PATH := $(call my-dir)


# the library
# the remotedisplay library
# ============================================================
# ============================================================
include $(CLEAR_VARS)
include $(CLEAR_VARS)


@@ -23,7 +23,7 @@ LOCAL_MODULE:= com.android.media.remotedisplay
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_TAGS := optional


LOCAL_SRC_FILES := \
LOCAL_SRC_FILES := \
            $(call all-subdir-java-files) \
            $(call all-java-files-under, java) \
            $(call all-aidl-files-under, java)
            $(call all-aidl-files-under, java)


include $(BUILD_JAVA_LIBRARY)
include $(BUILD_JAVA_LIBRARY)
+0 −1
Original line number Original line Diff line number Diff line
@@ -25,4 +25,3 @@ with the framework in a new API. That API isn't ready yet so this
library is a compromise to make new capabilities available to the system
library is a compromise to make new capabilities available to the system
without exposing the full surface area of the support library media
without exposing the full surface area of the support library media
route provider protocol.
route provider protocol.
Loading