NFC Secure Element Support

RESOLVED FIXED in Firefox 38, Firefox OS v2.2

Status

Firefox OS
NFC
RESOLVED FIXED
4 years ago
2 years ago

People

(Reporter: psiddh, Assigned: psiddh)

Tracking

(Blocks: 5 bugs, {dev-doc-needed, verifyme})

unspecified
2.2 S6 (20feb)
dev-doc-needed, verifyme
Dependency tree / graph
Bug Flags:
in-testsuite +

Firefox Tracking Flags

(feature-b2g:2.2+, tracking-b2g:backlog, firefox36 wontfix, firefox37 wontfix, firefox38 fixed, b2g-v2.2 fixed, b2g-master fixed)

Details

Attachments

(16 attachments, 74 obsolete attachments)

2.82 KB, text/plain
Details
95.81 KB, image/png
Details
376.10 KB, image/png
Details
97.77 KB, image/png
Details
6.67 KB, patch
smaug
: review+
Details | Diff | Splinter Review
79 bytes, text/plain
Details
1.51 KB, patch
tauzen
: review+
Details | Diff | Splinter Review
18.69 KB, patch
tauzen
: review+
Details | Diff | Splinter Review
19.09 KB, patch
tauzen
: review+
Details | Diff | Splinter Review
16.66 KB, patch
tauzen
: review+
Details | Diff | Splinter Review
4.77 KB, patch
tauzen
: review+
Details | Diff | Splinter Review
4.57 KB, patch
tauzen
: review+
Details | Diff | Splinter Review
9.36 KB, patch
tauzen
: review+
Details | Diff | Splinter Review
1.51 KB, patch
Details | Diff | Splinter Review
9.32 KB, patch
Details | Diff | Splinter Review
4.61 KB, patch
Details | Diff | Splinter Review
(Assignee)

Description

4 years ago
User Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.11 (KHTML, like Gecko) Ubuntu/12.04 Chromium/20.0.1132.47 Chrome/20.0.1132.47 Safari/536.11

Steps to reproduce:

No Secure Element APIs for NFC



Expected results:

Support for Secure Element APIs should be present for a commercial Wallet like solution
(Assignee)

Updated

4 years ago
Blocks: 860906
(Assignee)

Comment 1

4 years ago
Created attachment 758658 [details]
(NFC) Secure Element Proposed High Level Architecture
(Assignee)

Comment 2

4 years ago
Created attachment 758660 [details]
(NFC) Secure Element Proposed High Level Architecture
Attachment #758658 - Attachment is obsolete: true

Updated

4 years ago
Assignee: nobody → psiddh
OS: Linux → All
Hardware: x86_64 → All
(Assignee)

Updated

4 years ago
Blocks: 884594
Is there any documentation for how these "secure elements" work? Like what use cases they are trying to address, and a high level description of how they address them?

Comment 4

4 years ago
very high-level blurb:
http://www.globalplatform.org/mediaguideSE.asp

On a technical level, a SE is a tamper-resistent Java Card platform. They are often used in payment solutions (e.g., Google Wallet). The payment process is handled by a Cardlet running on the SE that communicates directly with the POS (Point of Sales) terminal via NFC. SE can also be used for other applications such as secure vaults. We implement part of the Global Platform API for APDU exchange with the SE.
(Assignee)

Comment 5

4 years ago
Some more information here , SE on Android

http://nelenkov.blogspot.nl/2012/08/accessing-embedded-secure-element-in.html
Depends on: 749325

Updated

4 years ago
Blocks: 894691
No longer blocks: 860906

Updated

4 years ago
Component: DOM: Device Interfaces → NFC
Product: Core → Boot2Gecko
Version: Trunk → unspecified
No longer depends on: 749325

Comment 6

4 years ago
Created attachment 804860 [details]
API Proposal for various secure elements

Comment 7

4 years ago
At this moment, I'm focusing on the UICC secure element, but in the future, the platform should be able to treat dual sims and other elements in a consistent manner. 

To enable us to develop step-by-step, I'd like to propose the API attached. 
(I'll revise it to webidl format soon)

Comment 8

4 years ago
Created attachment 806426 [details]
API Proposal for various secure elements

The attached file is a proposal for SecureElement API in webidl format.
It consists of (1)MozSeManger, SecureElement and SeChannel definition and (2)modification on the MozIccManger.
Taking into consideration on private comments and https://bugzilla.mozilla.org/show_bug.cgi?id=894691, I omitted the basic-channel access. Any comments are highly appreciated.
Attachment #804860 - Attachment is obsolete: true
Attachment #806426 - Attachment is patch: true
Attachment #806426 - Attachment is patch: false
Hi, Junichi-san

If you're purposing an API for SE, maybe we need to file another bug for that, because this bug is focus on the 'NFC' secure element.

For the file you uploaded, 
you can format it as a patch.
see https://developer.mozilla.org/en-US/docs/Mercurial_FAQ#How_can_I_generate_a_patch_for_somebody_else_to_check-in_for_me.3F

Using a patch here is easier to comment on the particular line. So I don't have to copy & paste the code into this comment again.

And split it to two parts.
1. remove the API from IccManager
2. SE API

And for the newer API, we no longer prefix with 'Moz', see https://wiki.mozilla.org/User:Overholt/APIExposurePolicy
(nsIDOMMozIccManager is landed before this annoucement)

Back to your patch

partial interface nsIDOMMozIccManager {
   /**
    * Returns SecureElement object belonging UICC
    *
    * Returned object should be identical to an element of mozSeManager.getSecureElements('SIM');
    */
   SecureElement getSecureElement();

Why do we need this? Can't this be done by your SE-API?

/**
 * SeManger
 * Manages all secure elements on the platform
 */
interface MozSeManager {

We prefer full name in the interface,
SecureElementManager is more clear here.


  /**
   * Select a secure element for NFC card-emulation mode
   */
  attribute MozSecureElement cardEmulator;

is this card emulation mode NFC-only? For example UICC and ASSD won't have this mode ?
if it's nfc-only, we should consider do it in this bug.
(We'd like to divide things into small parts to make it easier)

interface MozSecureElement {

  /* e.g. 'SIM***', 'eSE***' or 'SD***' */
  readonly attribute DOMString name;


You could use an enum for that.

But if we're not going to implement ASSD(Secure Element on SDcard), we shouldn't list it here, or need to file another bug for it.

 /**
   * Opens channel and select the specified application.
   *
   * @param ApplicationId is application id expressed in a hex string, e.g. 'ff00dd11bb22..'
   *
   * @return req.result will be a Channel object if succeeded.
   *
   * Note: We shortened manager-provider-session-channel sequence presented at
   *   https://bugzilla.mozilla.org/show_bug.cgi?id=840780#c27
   */
  DOMRequest openChannel(DOMString applicationId);

How do you get applicationId here?
For UICC I know we still need to expose it to Web and I will work on that soon, but how about NFC? 


And do we need TransactionListener here?

Comment 10

4 years ago
Hi, Yoshi-san,

Thank you for comments.

I'll revise my 'patch' according to the style you told soon.
Here are some questions and answers.

> If you're purposing an API for SE, maybe we need to file another bug for
> that, because this bug is focus on the 'NFC' secure element.

This bug is for any secure elements(eSE, SIM, SD) co-working with NFC, isn't it?
I think they should supports the same API and should work with NFC in a consistent manner,
so that this bug seems the best place to discuss such a API.
 

> partial interface nsIDOMMozIccManager {
>    /**
>     * Returns SecureElement object belonging UICC
>     *
>     * Returned object should be identical to an element of
> mozSeManager.getSecureElements('SIM');
>     */
>    SecureElement getSecureElement();
> 
> Why do we need this? Can't this be done by your SE-API?

Yes, it can.
I put it for developer's convenience and for consistency to the current IccManager API
(It has iccOpen(), iccExchangeAPDU() and iccClose()) 


> 
>   /**
>    * Select a secure element for NFC card-emulation mode
>    */
>   attribute MozSecureElement cardEmulator;
> 
> is this card emulation mode NFC-only? For example UICC and ASSD won't have
> this mode ?
> if it's nfc-only, we should consider do it in this bug.
> (We'd like to divide things into small parts to make it easier)


It's for any secure elements.
I think any secure elements should support the same API and
no nfc-embeded-se specialized methods are needed.


> interface MozSecureElement {
> 
>   /* e.g. 'SIM***', 'eSE***' or 'SD***' */
>   readonly attribute DOMString name;
> 
> 
> You could use an enum for that.
> 
> But if we're not going to implement ASSD(Secure Element on SDcard), we
> shouldn't list it here, or need to file another bug for it.

If a handset supports multiple sim cards, the name might be 'SIM0' and 'SIM1' so that
enum cannot be used here.



>  /**
>    * Opens channel and select the specified application.
>    *
>    * @param ApplicationId is application id expressed in a hex string, e.g.
> 'ff00dd11bb22..'
>    *
>    * @return req.result will be a Channel object if succeeded.
>    *
>    * Note: We shortened manager-provider-session-channel sequence presented
> at
>    *   https://bugzilla.mozilla.org/show_bug.cgi?id=840780#c27
>    */
>   DOMRequest openChannel(DOMString applicationId);
> 
> How do you get applicationId here?
> For UICC I know we still need to expose it to Web and I will work on that
> soon, but how about NFC? 

UI app, which accesses SE, should know the applicationID.
(It could be embedded in the app or sent from a server)

No plan for NFC(eSE) currently but in the future it should be accessed
in the same manner as the UICC-secure-element is accessed.



> And do we need TransactionListener here?

It's a good point. How about to use system message?

/* manifest */
 messages { 'secure-element-transaction'...}
/* app */
 navigator.mozSetMessageHandler('secure-element-transaction', function(evt) {
   // ref. NFC Handset APIs & Req. v3.0 sec 4.5.1
   evt.name; // e.g. 'SIM0'
   evt.port; // e.g. '0'
   evt.aid;  // e.g. 'aabbcc0011...'
   evt.data; // any byte[]
}

Comment 11

4 years ago
Junichi-san,

There is currently an initiative at W3C, within the SysApps Working group, to define such SE API. We are still at early stage of this specification, it is thus a good opportunity for you to contribute and help. It is also a good opportunity to leverage on the work that have been done by contributing companies, and define+use an API which is more likely to be available in next-generation web runtimes.
Actually your proposed API is close to the initial proposal we have. Regarding the transaction, the intent (that has to be documented) is that all communications inside a channel happen in a transaction. A transaction is created in Open?Chanel(), and terminated in channel.close()
Please check: http://opoto.github.io/secure-element/
(Assignee)

Comment 12

4 years ago
Created attachment 809313 [details]
nsISecureElementInterface.idl
(Assignee)

Comment 13

4 years ago
Created attachment 809314 [details]
nsIDOMNavigatorSecureElementManager.idl
(Assignee)

Comment 14

4 years ago
Created attachment 809315 [details]
nsIDOMSecureElementManager.idl
(Assignee)

Comment 15

4 years ago
Created attachment 809317 [details]
nsIDOMNavigatorSecureElementManager.idl
(Assignee)

Comment 16

4 years ago
Attached 4 IDLs, main one being nsISecureElementInterface.idl. These are initial (draft version) IDLs on FxOS. Using these interfaces, we were able to access UICC and embedded SE on our prototype implementation.
Blocks: 860906

Updated

4 years ago
blocking-b2g: --- → 1.4+
removing 1.4+ flag.
blocking-b2g: 1.4+ → ---
(Assignee)

Comment 18

4 years ago
Created attachment 8368237 [details]
FxOS_SecureElement_Architecture_v1.png

Firefox Secure Element Architecture Updated (As per the consensus arrived during Poland Work Week)
Attachment #758660 - Attachment is obsolete: true
(Assignee)

Comment 19

4 years ago
Created attachment 8374418 [details]
MozSecureElementManager.webidl
Attachment #809313 - Attachment is obsolete: true
Attachment #809314 - Attachment is obsolete: true
Attachment #809315 - Attachment is obsolete: true
Attachment #809317 - Attachment is obsolete: true
(Assignee)

Comment 20

4 years ago
Created attachment 8374419 [details]
MozSecureElementObjects.webidl
(Assignee)

Updated

4 years ago
Depends on: 979158
(Assignee)

Updated

4 years ago
Attachment #8374418 - Flags: feedback?(jonas)
(Assignee)

Updated

4 years ago
Attachment #8374419 - Flags: feedback?(jonas)
Blocks: 979158
No longer depends on: 979158

Updated

4 years ago
Blocks: 979767
Depends on: 921320
Sorry about the slow feedback here. I've reached out to the FirefoxOS security team and need their help in understanding various basics of secure elements. We might rope you into those conversations too if we can make timezones work.
(Assignee)

Comment 22

4 years ago
Sure Jonas. Also Ming Yin from DT ,Germany may also like to join.
(In reply to Jonas Sicking (:sicking) from comment #21)
> Sorry about the slow feedback here. I've reached out to the FirefoxOS
> security team and need their help in understanding various basics of secure
> elements. We might rope you into those conversations too if we can make
> timezones work.

Did you? Who did you talk to? PS I am in Taipei if that helps. Looks like this is stuff to review here, so I will get someone on it as soon as possible.
Ah you are talking about the mailing list post, ok I am on the same page now...

Comment 25

4 years ago
I don't know how far this has progressed by IMO an SE API for SIMs or uSDs is not that interesting because embedded SEs are rather different and can also provide much higher functionality.

http://images.apple.com/ipad/business/docs/iOS_Security_Feb14.pdf
https://www.samsungknox.com/en/solutions/knox/technical
http://webpki.org/papers/PKI/pki-webcrypto.pdf#page=2

NFC is another thing, particularly after HCE has been introduced in Android.

Comment 26

4 years ago
Hi Abders, can you please explain a little bit more about your first comment "embedded SEs are rather different and can also provide much higher functionality"?

To my understanding, this proposed SE API targets to provide a generic communication interface between the  certified web applications and the possible kinds of Secure Elements(SIM/eSE/SD/Cloud-SE/...) on device. It focuses on transport API, instead of the "secure" application scenarios on the top of it. WIth this API as enabling functions, many security-sensitive applications can be built on top of it.

Currently, one of usage example of SE API is the mobile wallet. But, it should be not only limited to payment/m-wallet case. I can imagine that there should be many other applications, which can profit from the SE-based strong security features. For instance, 

1) mobile electronic passport
2) secure storage for different credentials/keys/digital-signature/...;
3) authentication services;
4) ticketing/access;
5) on-card crypto-functions support;
etc.

I don't think, "SE + exported SE-API" is a solution for overall OS security, but it can definitely contribute to OS and application. security.
(Assignee)

Comment 27

4 years ago
Created attachment 8396843 [details]
MozSecureElementManager.webidl
Attachment #8374418 - Attachment is obsolete: true
Attachment #8374418 - Flags: feedback?(jonas)
(Assignee)

Comment 28

4 years ago
Created attachment 8396844 [details]
MozSecureElementObjects.webidl
Attachment #8374419 - Attachment is obsolete: true
Attachment #8374419 - Flags: feedback?(jonas)
Attachment #8396844 - Flags: feedback?(jonas)
(Assignee)

Updated

4 years ago
Attachment #8396843 - Flags: feedback?(jonas)
(Assignee)

Comment 29

4 years ago
Created attachment 8396852 [details] [diff] [review]
SE_Api_Snippet_Usage.patch

Comment 30

4 years ago
The code outlined in

https://bug879861.bugzilla.mozilla.org/attachment.cgi?id=8396852

was during the W3C TPAC 2013 in China, characterized by a Google spokesman as "the scariest API he had ever seen". Although that was probably a bit of stretch, there are some fundamental issues here which (I guess) means that this code can only be featured in a trusted web application which greatly limits utility.

Both Google's U2F and your truly's SKS/KeyGen2 achieve similar qualities *without* introducing such requirements.  One of the core ingredients is by defining the SE itself which means that there's no opaque channel moving arbitrary APDUs or bytes.  This allows the UA to monitor and control the entire process, including alerting the user when required.

Comment 31

4 years ago
It is possible that I have misunderstood parts of this but to me HCE and freestanding SE operations are very different and do not gain by using a common API.  Although my knowledge of HCE is limited, it seems that some kind of virtual/driver concept would be suitable since the "card" can (as Ming described) be anything.

Comment 32

4 years ago
I think,  at least following ecosystem players would benefit from the introduction of the SE API.

1. Firefox OS User
The User's mobile internet & proximity services could be better protected (if required);

2. Application developers
they create security sensitive services using SE API, including mobile payment services, mobile authentication services, mobile banking service, mobile identity service, etc.

3. SE issuer
by opening up his secure element, new business opportunities could be introduced.

4. Handset OEM 
SE is regarded as a unique selling point to many NFC business solution partners, such as operators, financial service providers, etc.

5. Mozilla
support partners's NFC business models and contribute to the mobile internet service security/identiy.


Surely, SE itself is not a "complete" OS/App security solution, instead it is just a quite nice addon.

Comment 33

4 years ago
Regarding the point "HCE and freestanding SE", I wish, Firefox OS could keep these technology choices open and support more than one business models simultaneously.

Comment 34

4 years ago
(In reply to Ming Yin from comment #33)
> Regarding the point "HCE and freestanding SE", I wish, Firefox OS could keep
> these technology choices open and support more than one business models
> simultaneously.

Yes, Android and iOS can easily do that through their rich APIs.
Doing that with web technology should be doable but I don't know how.

For new NFC services, I wouldn't bother with HCE at all, an emulation of URL + HTTP GET over NFC seems like a much easier way including full compliance with the web "as is".

Which (if true) would reduce the application spectrum for HCE/SE to something much more manageable...

Disclaimer: I'm not particularly versed in NFC or EMV, my interest and line of work is in the OS/TEE/SE field.

Updated

3 years ago
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Reference sharing from end user UI level perspective.
"MasterCard PayPass UI/UX Design Guide for mobile application developers"

http://www.mastercard-mobilepartner.com/pdf/MMPP_UIDesignGuide_v1-0.pdf

Comment 36

3 years ago
The current plan is probably obsolete:

http://newsroom.mastercard.com/press-releases/mastercard-to-use-host-card-emulation-hce-for-nfc-based-mobile-payments

Comment 37

3 years ago
For me, HCE(Host Card Emulation) and the SE API are actually two different issues: 

SE API provides the generic/unified API to allow for the APDU-based logical channel communication between the certified gaia apps and the underlaying secure element applications. From the communication direction, it is top->down communication!
As an example, in case that a certified gaia app wants to communicate with a SIM applicaiton, the communication path would be established as follows:  
GAIA App -> SE API/DOM Impl-> SE ACF(AccessControlFunction) -> RadioInterfaceLayer -> RIL Worker -> RIL Stack -> Baseband -> SIM application

HCE provides a new way how to do NFC Card Emulation. Besides the SIM&eSE based Card Emulations, HCE becomes the 3rd option, which routes the incoming APDU traffic from NFC controller to the Host/OS. From the communication direction, it is bottom->up communication!
As example, the typical communication path could look as follows:  
POS Terminal -> NFC Controller -> NFC daemon -> NFC worker -> Nfc.js -> Gaia Application

Comment 38

3 years ago
(In reply to Ming Yin from comment #37)
> For me, HCE(Host Card Emulation) and the SE API are actually two different
> issues:

Me too :-)

> 
> SE API provides the generic/unified API to allow for the APDU-based logical
> channel communication between the certified gaia apps and the underlaying
> secure element applications. From the communication direction, it is
> top->down communication!
> As an example, in case that a certified gaia app wants to communicate with a
> SIM applicaiton, the communication path would be established as follows:  
> GAIA App -> SE API/DOM Impl-> SE ACF(AccessControlFunction) ->
> RadioInterfaceLayer -> RIL Worker -> RIL Stack -> Baseband -> SIM application

This is the way the W3C SE API ( http://opoto.github.io/secure-element ) is designed.

A "problem" is that this API [essentially] only applies to SIM-cards. Other SE designs out there like SKS and U2F do not need certified applications (since they are intended to be fully integrated in the UA), and also work at a higher level (like JCE, .NET, NSS and PKCS #11), which existing secure application developers are comfortable with.

An even bigger problem is that the SIM-card is inaccessible for "outsiders" making this scheme unattractive for all but operators.

Due to the above mobile banking won't use this solution and that's a non-starter in my world.

Anyway, it's not my decision, I just wanted to air my opinion that this is not where Mozilla's competition is going.   Embedded security using TEEs is already shipping in newer Android phones and Apple's A7 processor hosts an even more advanced security solution.

> 
> HCE provides a new way how to do NFC Card Emulation. Besides the SIM&eSE
> based Card Emulations, HCE becomes the 3rd option, which routes the incoming
> APDU traffic from NFC controller to the Host/OS. From the communication
> direction, it is bottom->up communication!
> As example, the typical communication path could look as follows:  
> POS Terminal -> NFC Controller -> NFC daemon -> NFC worker -> Nfc.js -> Gaia
> Application

Comment 39

3 years ago
(In reply to Anders Rundgren from comment #38)
> (In reply to Ming Yin from comment #37)
> > For me, HCE(Host Card Emulation) and the SE API are actually two different
> > issues:
> 
> Me too :-)
> 
> > 
> > SE API provides the generic/unified API to allow for the APDU-based logical
> > channel communication between the certified gaia apps and the underlaying
> > secure element applications. From the communication direction, it is
> > top->down communication!
> > As an example, in case that a certified gaia app wants to communicate with a
> > SIM applicaiton, the communication path would be established as follows:  
> > GAIA App -> SE API/DOM Impl-> SE ACF(AccessControlFunction) ->
> > RadioInterfaceLayer -> RIL Worker -> RIL Stack -> Baseband -> SIM application
> 
> This is the way the W3C SE API ( http://opoto.github.io/secure-element ) is
> designed.
> 
> A "problem" is that this API [essentially] only applies to SIM-cards. Other
> SE designs out there like SKS and U2F do not need certified applications
> (since they are intended to be fully integrated in the UA), and also work at
> a higher level (like JCE, .NET, NSS and PKCS #11), which existing secure
> application developers are comfortable with.
> 
> An even bigger problem is that the SIM-card is inaccessible for "outsiders"
> making this scheme unattractive for all but operators.
> 
> Due to the above mobile banking won't use this solution and that's a
> non-starter in my world.
> 
> Anyway, it's not my decision, I just wanted to air my opinion that this is
> not where Mozilla's competition is going.   Embedded security using TEEs is
> already shipping in newer Android phones and Apple's A7 processor hosts an
> even more advanced security solution.

To be noted, this SE API(similiar to W3C SE API) doesn't only apply to SIM-cards!
Currently, we focus only on existing hardware-based SE solutions, such as SIM/eSE/SD-card. But, it could be technically feasible to integrate software-based solutions or even the SE solution in the cloud. The important thing for me is to offer the web developers a consistent API to various security/privacy related data/functions.

> 
> > 
> > HCE provides a new way how to do NFC Card Emulation. Besides the SIM&eSE
> > based Card Emulations, HCE becomes the 3rd option, which routes the incoming
> > APDU traffic from NFC controller to the Host/OS. From the communication
> > direction, it is bottom->up communication!
> > As example, the typical communication path could look as follows:  
> > POS Terminal -> NFC Controller -> NFC daemon -> NFC worker -> Nfc.js -> Gaia
> > Application

Comment 40

3 years ago
(In reply to Ming Yin from comment #39)
> (In reply to Anders Rundgren from comment #38)
> > (In reply to Ming Yin from comment #37)
> > > For me, HCE(Host Card Emulation) and the SE API are actually two different
> > > issues:
> > 
> > Me too :-)
> > 
> > > 
> > > SE API provides the generic/unified API to allow for the APDU-based logical
> > > channel communication between the certified gaia apps and the underlaying
> > > secure element applications. From the communication direction, it is
> > > top->down communication!
> > > As an example, in case that a certified gaia app wants to communicate with a
> > > SIM applicaiton, the communication path would be established as follows:  
> > > GAIA App -> SE API/DOM Impl-> SE ACF(AccessControlFunction) ->
> > > RadioInterfaceLayer -> RIL Worker -> RIL Stack -> Baseband -> SIM application
> > 
> > This is the way the W3C SE API ( http://opoto.github.io/secure-element ) is
> > designed.
> > 
> > A "problem" is that this API [essentially] only applies to SIM-cards. Other
> > SE designs out there like SKS and U2F do not need certified applications
> > (since they are intended to be fully integrated in the UA), and also work at
> > a higher level (like JCE, .NET, NSS and PKCS #11), which existing secure
> > application developers are comfortable with.
> > 
> > An even bigger problem is that the SIM-card is inaccessible for "outsiders"
> > making this scheme unattractive for all but operators.
> > 
> > Due to the above mobile banking won't use this solution and that's a
> > non-starter in my world.
> > 
> > Anyway, it's not my decision, I just wanted to air my opinion that this is
> > not where Mozilla's competition is going.   Embedded security using TEEs is
> > already shipping in newer Android phones and Apple's A7 processor hosts an
> > even more advanced security solution.
> 
> To be noted, this SE API(similiar to W3C SE API) doesn't only apply to
> SIM-cards!

True, but using other cards is more like a "theoretical" possibility.
Who would buy an uSD smart card?

> Currently, we focus only on existing hardware-based SE solutions, such as
> SIM/eSE/SD-card. But, it could be technically feasible to integrate
> software-based solutions or even the SE solution in the cloud. The important
> thing for me is to offer the web developers a consistent API to various
> security/privacy related data/functions.

Since there is no standard (de-facto or real) this goal is simply put not achievable.

Mozilla have two choices:  1) Try to set a standard.  2) Wait for Google to set the standard.

It is obviously a choice between pest or cholera.

I have personally settled on "pest" since waiting is boring and negatively affects my self-esteem as an engineer :-)

> 
> > 
> > > 
> > > HCE provides a new way how to do NFC Card Emulation. Besides the SIM&eSE
> > > based Card Emulations, HCE becomes the 3rd option, which routes the incoming
> > > APDU traffic from NFC controller to the Host/OS. From the communication
> > > direction, it is bottom->up communication!
> > > As example, the typical communication path could look as follows:  
> > > POS Terminal -> NFC Controller -> NFC daemon -> NFC worker -> Nfc.js -> Gaia
> > > Application
blocking-b2g: --- → backlog
Comment on attachment 8396843 [details]
MozSecureElementManager.webidl

Sending these over to Yoshi
Attachment #8396843 - Flags: feedback?(jonas) → feedback?(allstars.chh)
Attachment #8396844 - Flags: feedback?(jonas) → feedback?(allstars.chh)
Sorry for the long wait, Sidd.
Now I am working on test case both on Gecko and Gaia side. 
I'll start to check this next week.
Comment on attachment 8396843 [details]
MozSecureElementManager.webidl


>enum SecureElementType {
>  "uicc",
>  "eSE",
>  "sdCard"
>  "other"
>};
>
Only add the types you plan to support in the first version.

>enum SecureElementError {
>  "unknown",
>  "io",
>  "security",
>  "invalid_state",
>  "invalid_value",
>  "no_channel",
>  "no_application",
>  "closed"
>};
>
Please document when these errors will happen.


>[NoInterfaceObject,
> Func="Navigator::HasSecureElementAdminSupport"]
>interface MozNfcSecureElementAdmin {
>
Why the Nfc?
Isn't this API generic to all SEs?
 

>  /**
>   * Card Emulation Support Modes
>   */
>  const long CE_MODE_DEVICE_POWERED_ON      = 0x01;
>  const long CE_MODE_DEVICE_POWERED_OFF     = 0x02;
>  const long CE_MODE_DEVICE_LOW_POWER_MODE  = 0x04;
>
>  /**
>   * Set the default SecureElement
>   *
>   * @param type
>   *        One of SecureElementType. "uicc" or "eSE" etc..
>   */
>  DOMRequest setDefaultSecureElement(SecureElementType type);
>
>  /**
>   * Swicth to another SecureElement type
>   *
>   * @param type
>   *        One of SecureElementType. "uicc" or "eSE" etc..
>   */
>  DOMRequest switchSecureElement(SecureElementType type);
>
>  /**
>   * Sets the Card Emulation Support mode. This interface is
>   * used by privileged content to notify nfc hardware to
>   * support card emulation mode, say even in low power mode.
>   *
>   * @param type
>   *        One of CE_MODE_DEVICE_* (or) masked values of CE_MODE_DEVICE_*
>   */
>  DOMRequest setCardEmulationMode(long mode);
>};
Remove this, this is about card emulation.
Please implement CE in another bug.


>
>
>[JSImplementation="@mozilla.org/navigatorSecureElementManager;1",
> NavigatorProperty="mozSecureElementManager",
> Func="Navigator::HasSecureElementManagerSupport"]
>interface MozSecureElementManager : EventTarget {
>
>  /**
>   * Retrieves the secure element of a given type.
>   *
>   * @return a DOMRequest.
>   *        The request's result will be an instance
>   *        of MozSecureElement of requested type
>   */
>  DOMRequest getSecureElement(SecureElementType seType);
>
>
>  /**
>   * Retrieves all the secure elements available on the device.
>   *
>   * @return a DOMRequest.
>   *        The request's result will be an array of instances
>   *        of MozSecureElement
>   */
>  DOMRequest getSecureElements();
>
s/SecureElement/Reader/g
After checking MozSecureElement (in another WebIDL), I think it should be named as
'Reader', not 'SecureElement'.

Also refer to OpenMobile API.

And it seems you don't have callback for the reader is mounted/unmounted?
How does the web know what's the correct timing to call getSecureElement(s) ?

>  /**
>   * Get the current Card Emulation Support mode.
>   */
>  DOMRequest getCardEmulationMode();
>
>  /**
>   * Event to notify when external reader access an application stored on Secure Element
>   *
>   * Per ETSI TS 102.622, HCI event EVT_TRANSACTION is notified using this event handler
>   * This event  provides a mechanism to inform authorised / certified Gaia wallet
>   * applications of Transaction Event(s) and it should contain the the Secure
>   * Element name and the AID of the applet which triggered the transaction and
>   * PARAMETERS holding the payload conveyed by the HCI EVT_TRANSACTION event.
>   */
>  attribute EventHandler onsetransaction;
>
Remove CE.

>};
>
>// Mozilla Only
>partial interface MozSecureElementManager {
>   [ChromeOnly]
>   void eventListenerWasAdded(DOMString aType);
>   [ChromeOnly]
>   void eventListenerWasRemoved(DOMString aType);
>};
>
>MozSecureElementManager implements MozNfcSecureElementAdmin;
>
Attachment #8396843 - Flags: feedback?(allstars.chh) → feedback-
Comment on attachment 8396844 [details]
MozSecureElementObjects.webidl

Next time consider use patch format so we can review it on Bugzilla instead of doing 'Edit Attachments as Comment'.
Also consider renaming this file to MozSecureElement.webidl.

For the newer APIs, please use Promise instead of DOMRequest.

>[JSImplementation="@mozilla.org/secureelement/SecureElement;1"]
>interface MozSecureElement {

This should be named MozReader

>
>  // 'true' if a secure element is present 
>  readonly attribute boolean  isSEPresent;
>
>  // Type of SecureElement
>  readonly attribute SecureElementType type;
>
>  /**
>   * Connect to the Secure Element
>   *
>   * @return a DOMRequest.
>   *        The request's result will be an instance of MozSecureElementSession
>   */
>  DOMRequest connect();
openSession

>
>  /**
>   * Disconnect from the Secure Element
>   */
>  DOMRequest disconnect();
>};
>
>[JSImplementation="@mozilla.org/secureelement/SecureElementSession;1"]
>interface MozSecureElementSession {
>  
>  // Handle of Execution Environment
>  readonly attribute long handle;
What's this for?

>
>  // Status of current session
>  readonly attribute boolean isActive;

Under what circurstances it will be inactive?

>
>  /**
>   * Connect to the Secure Element
>   *
The comments seems not precise.
This API looks to me is to 'open a Basic/Logical channel to communicate with SE.

>   * @param aid
>   *     Application Identifier of the Card Applet on the secure element. If 'null'
>   *     then default card applet is selected
>   * @param isLogicalChannel
>   *     Optional flag representing if the current channel attempted to be
>   *     opened is a Logical channel or a Basic Channel (Channel '0').
>   *     Default value is treated as a 'logical channel'.
>   *
>   * @return a DOMRequest.
>   *        The request's result will be an instance of MozSecureElementChannel
>   */
>  DOMRequest openChannel(DOMString aid, optional boolean isLogicalChannel = true);
>
openBasicChannel and openLogicalChannel

>  /**
>   * Close the active connection with the Secure Element. This request will also
>   * close all other active channels associated with this session.
>   */
>  DOMRequest close();
>
>
Do we also need getATR() for this interface?

>};
>
>[JSImplementation="@mozilla.org/secureelement/SecureElementChannel;1"]
>interface MozSecureElementChannel {
>  
>  // Handle of current channel that represents a logical connection with the SE
>  readonly attribute long channel;
>
What's this for?

>  // boolean flag indicating if the current channel is a 'Logical Channel' or not
>  readonly attribute boolean isLogicalChannel;
isBasicChannel.

Refer to Open Mobile API, W3C SE API, Webinos SE API, and seek-for-android SE API.
They all use 'isBasicChannel'.


>  /**
>   * Transmits the APDU command to the secure element.
>   *
>   * @param apdu
>   *     uint8 array of APDU SE Command
>   * [Strutcure of APDU SE Command]
>   * 1 Byte         : Class Byte                              - cla
>   * 1 Byte         : Instruction Byte                        - ins
>   * 1 Byte         : First Octet of Parameters Byte          - p1
>   * 1 Byte         : Second Octet of Parameters Byte         - p2
>   * Len of apdu    : uint8 array of APDU                     - data
Len of apdu? it sounds like you are referring the len parameter below?

>   * unsigned short : The length of the expected
>   *                  response data or -1 if none is expected - len

From ISO 7816-4, shouldn't this parameter name 'le' ?

>   *


Shouldn't this be an interface like MozSECommand ? 
As you did for SERespose?

>   * @return a DOMRequest.
>   *        The request's result will be an instance of SEResponse
>   */
>  DOMRequest transmit(Uint8Array apdu);
>
>  /**
>   * Close the active channel
>   */
>  DOMRequest close();
>

Do we also need isClosed()?
>};
>
>[Constructor(optional octet sw1, optional octet sw2, Uint8Array data)]
Why are sw1 and sw2 optional? Could data be nullable?

>interface SEResponse {
you remove Moz prefix on purpose ?

>  
>  // First octet of response's status word
>  readonly attribute octet        sw1;
>
>  // Second octet of response's status word
>  readonly attribute octet        sw2;
>
>  // The response's data field bytes
>  readonly attribute Uint8Array   data;
>};
>
Attachment #8396844 - Flags: feedback?(allstars.chh) → feedback-
(In reply to Yoshi Huang[:allstars.chh] from comment #44)
> >[JSImplementation="@mozilla.org/secureelement/SecureElement;1"]
> >interface MozSecureElement {
> 
> This should be named MozReader
> 
Or MozSecureElementReader

Comment 46

3 years ago
Quick Note: Currently all NFC payment user stories are covered under: Bug 979152, Bug 979154, Bug 979157, Bug 979158, 884478. All the dependencies for those should be marked in those meta bugs.
(Assignee)

Comment 47

3 years ago
Created attachment 8438175 [details] [diff] [review]
(v1.1) Secure Element APIs - Inital Draft
Attachment #8396843 - Attachment is obsolete: true
Attachment #8396844 - Attachment is obsolete: true
Attachment #8396852 - Attachment is obsolete: true
Attachment #8438175 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 48

3 years ago
Hi Yoshi,
Thanks for your comments.

>[NoInterfaceObject,
> Func="Navigator::HasSecureElementAdminSupport"]
>interface MozNfcSecureElementAdmin {
>
>>Why the Nfc?
>>Isn't this API generic to all SEs?
MozSEAdmin (renamed from 'MozNfcSecureElementAdmin' to 'MozSEAdmin) interface object may be used by only privileged apps such as System app or say settings.
Through settings app (should there be a setting option, say ) using these apis, default SE can be set. (could be UICC or eSE).

>Remove this, this is about card emulation.
>Please implement CE in another bug.
Ok

>s/SecureElement/Reader/g
>>After checking MozSecureElement (in another WebIDL), I think it should be named as
>>'Reader', not 'SecureElement'
Prefixed all the interfaces with MozSExxx. Is it ok?

>And it seems you don't have callback for the reader is mounted/unmounted?
>How does the web know what's the correct timing to call getSecureElement(s) ?
We had this question for NXP earlier to understand if NXP drivers notify these events. Since I wasn't sure, haven't added them.
I will follow up with NXP and update. For now, I have now added two event handlers 'onsepresent' and 'onseremoved'. 

>  readonly attribute long handle;
>> What's this for?
Actually this will be an internal handle. Now I have removed it from web idl. We may not need to put it in webIDL

>  readonly attribute boolean isActive;
>> Under what circurstances it will be inactive?
A reader may have several opened sessions. The intent of this attribute is to maintain the current active session among list of opened ones

> Do we also need getATR() for this interface?
Yes, right. Missed it.

>  readonly attribute long channel;
>> What's this for?
Whenever a channel is opened , the secure element gives an handle if successfully opened.
Channel interface is an object that manages this handle. 

> isBasicChannel.
> Refer to Open Mobile API, W3C SE API, Webinos SE API, and seek-for-android SE API.
> They all use 'isBasicChannel'.

Actually I was reading some old requirements for Payments from TMPL, and as per one of the requirements, we should not expose any interfaces to access Basic Channel (Channel # 0).
Because this may open up security issues. Maybe its better to not add support to access basic channel in webidls. What do you think ? 

> Do we also need isClosed()?
Maybe. Not sure at this point if its really needed.

I think rest of the comments were addressed as part of latest patch.
(Assignee)

Comment 49

3 years ago
Created attachment 8438568 [details] [diff] [review]
(v1.1) Secure Element APIs - Inital Draft
Attachment #8438175 - Attachment is obsolete: true
Attachment #8438175 - Flags: feedback?(allstars.chh)
Attachment #8438568 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 50

3 years ago
Created attachment 8438779 [details] [diff] [review]
(v1.2) Secure Element APIs - Inital Draft

Difference between v1.1 & v1.2 versions
- Removed MozSEAdmin interface to keep this patch clean. I will raise separate bugs for SEAdmin apis and CardEmulation support in webIDLs
- Also I have gone back and added 'openBasicChannel(...)'. Though UICC SE may restrict access to basic channel, but other SE's such eSE or even sdCard will have no such restriction. Therefore it is still a good idea for our APIs to be neutral / agnostic of underlying SE hardware.
Attachment #8438568 - Attachment is obsolete: true
Attachment #8438568 - Flags: feedback?(allstars.chh)
Attachment #8438779 - Flags: feedback?(allstars.chh)

Comment 51

3 years ago
Sid, there is a copy/paste error in MozSecureElement.webidl.
The attribute 'isBasicChannel' should be defined in MozSEChannel interface, instead of MozSESession interface.
Comment on attachment 8438779 [details] [diff] [review]
(v1.2) Secure Element APIs - Inital Draft

Review of attachment 8438779 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElement.webidl
@@ +5,5 @@
> +[JSImplementation="@mozilla.org/secureelement/SEReader;1"]
> +interface MozSEReader {
> +
> +  // 'true' if a secure element is present
> +  readonly attribute boolean  sePresent;

For boolean, prefix with 'is'.
extra space before sePresent.

@@ +32,5 @@
> +[JSImplementation="@mozilla.org/secureelement/SESession;1"]
> +interface MozSESession {
> +
> +  // Status of current session
> +  readonly attribute boolean isActive;

When will it be 'inactive'?
Or this variable will be false when we call reader.close() ?
then it seems 'isClosed' is more appropriate.

@@ +34,5 @@
> +
> +  // Status of current session
> +  readonly attribute boolean isActive;
> +
> +  // is it a basic channel ?

Is

@@ +35,5 @@
> +  // Status of current session
> +  readonly attribute boolean isActive;
> +
> +  // is it a basic channel ?
> +  readonly attribute boolean isBasicChannel;

What's this?

@@ +38,5 @@
> +  // is it a basic channel ?
> +  readonly attribute boolean isBasicChannel;
> +
> +  // Answer to Reset provided by the secure element, null if not provided
> +  readonly    attribute octet[] atr;

extra spaces before attr.

@@ +62,5 @@
> +   * @return If the operation is successful the promise is resolved with an instance of MozSEChannel.
> +   * NOTE: Some secure elements may deny opening a basic channel. In such a scenario, promise is resolved with SEIoError.
> +   */
> +  // Promise<MozSEChannel>
> +  Promise<Channel> openBasicChannel (octet[] aid);

remove <Channel>, and extra space before (octet[] aid)

@@ +65,5 @@
> +  // Promise<MozSEChannel>
> +  Promise<Channel> openBasicChannel (octet[] aid);
> +
> +  /**
> +   * Close the active communication channel to the application on Secure Element. This will also

Closes.

@@ +76,5 @@
> +};
> +
> +[JSImplementation="@mozilla.org/secureelement/SEChannel;1"]
> +interface MozSEChannel {
> +

you don't have isClosed().

@@ +78,5 @@
> +[JSImplementation="@mozilla.org/secureelement/SEChannel;1"]
> +interface MozSEChannel {
> +
> +  // Handle of current channel that represents a logical connection with the SE
> +  readonly attribute long channel;

Is this a channel ID?

Why do web apps needs to know the channelId given that we already have a MozSEChannel object?
Also why doesn't other objects like Reader, Session doesn't have a 'id'?

@@ +87,5 @@
> +   * @param apdu
> +   *     MozSECommand to be sent to secure element
> +   *
> +   * @return If success, the promise is resolved with the new created
> +   * MozSEResponse object. Otherwise, rejected with an error.

Can't MozSEResponse be used for error?

@@ +90,5 @@
> +   * @return If success, the promise is resolved with the new created
> +   * MozSEResponse object. Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEResponse>
> +  Promise transmit(MozSECommand apdu);

s/apdu/command/

@@ +93,5 @@
> +  // Promise<MozSEResponse>
> +  Promise transmit(MozSECommand apdu);
> +
> +  /**
> +   * Close the active channel

Closes, and add '.' at the end.

@@ +104,5 @@
> +
> +[Constructor(octet data, octet ins, octet p1, octet p2, optional ArrayBufferView data, optional octet le)]
> +interface MozSECommand {
> +
> +  // Interface that represents an APDU command to be sent to a secure element.

This comment should be moved to before 'Constructor'.

@@ +114,5 @@
> +  attribute unsigned short  le;     // The length of the expected
> +                                    // response data or -1 if none is expected - len
> +};
> +
> +[Constructor(Uint8Array data)]

When wll this cstor be used?

::: dom/webidl/MozSecureElementManager.webidl
@@ +12,5 @@
> +  "SEIoError",                  // I/O Error while communicating with the secure element
> +  "SEBadStateError",            // Error occuring as a result of bad state
> +  "SEInvalidChannelError,       // Opening a channel failed because no channel is available
> +  "SEInvalidApplicationError",  // The requested application was not found on the secure element
> +  "SEGenericError"              // Generic failures

Add '.' for all the comments above.

@@ +21,5 @@
> + Func="Navigator::HasSecureElementManagerSupport"]
> +interface MozSEManager : EventTarget {
> +
> +  /**
> +   * Retrieves the secure element of a given type.

s/secure element/reader/

@@ +27,5 @@
> +   * @return If success, the promise is resolved with the new created
> +   * MozSEReader object of requested type. Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReader>
> +  Promise getSEReader(SEType seType);

This interface totally looks useless to me.
How does web app know what seType are supported?
Doesn't it still need to call getSEReaders() to enumerate all the readers?
Then it could just get the reader in the array, why does it still need to call this API?

Unless you forgot to add a method 'getSupportedSETypes()',
but still, getSEReaders seems enough for us.

@@ +29,5 @@
> +   */
> +  // Promise<MozSEReader>
> +  Promise getSEReader(SEType seType);
> +
> +

extra line

@@ +31,5 @@
> +  Promise getSEReader(SEType seType);
> +
> +
> +  /**
> +   * Retrieves all the secure elements available on the device.

s/secure elemenets/readers/

@@ +41,5 @@
> +  Promise getSEReaders();
> +
> +  // Event handlers that listen on Secure element presence events
> +  attribute EventHandler onsepresent;
> +  attribute EventHandler onseremoval;

It looks to me this should be 'onsereaderpresent', insteadof 'onsepresent'.
Also what are the arguments containing in this callbacks?
How does we know which reader is added or removed?

@@ +42,5 @@
> +
> +  // Event handlers that listen on Secure element presence events
> +  attribute EventHandler onsepresent;
> +  attribute EventHandler onseremoval;
> +

extra line.
Attachment #8438779 - Flags: feedback?(allstars.chh) → feedback-
Comment on attachment 8438779 [details] [diff] [review]
(v1.2) Secure Element APIs - Inital Draft

Review of attachment 8438779 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElementManager.webidl
@@ +41,5 @@
> +  Promise getSEReaders();
> +
> +  // Event handlers that listen on Secure element presence events
> +  attribute EventHandler onsepresent;
> +  attribute EventHandler onseremoval;

I have second thoughts,
we might not need these two callbacks in the first draft, 
sorry I know I have asked this before, but removing them should be easier for us.

Comment 54

3 years ago
Tablets usually don't have SEs or UICCs.  What is Mozilla's solution here?

Worth looking into:
http://fidoalliance.org/specs/fido-u2f-raw-message-formats-v1.0-rd-20140209.pdf#page=8
(Assignee)

Comment 55

3 years ago
Created attachment 8440341 [details] [diff] [review]
(v1.3) Secure Element APIs - Inital Draft


@@ +32,5 @@
> +[JSImplementation="@mozilla.org/secureelement/SESession;1"]
> +interface MozSESession {
> +
> +  // Status of current session
> +  readonly attribute boolean isActive;

>> When will it be 'inactive'?
>> Or this variable will be false when we call reader.close() ?
>> then it seems 'isClosed' is more appropriate.

Yes the reader.close(), the boolean 'isActive' flag will be set to false.
Typically a reader may have several opened sessions. Intent was to have this flag set to 'inactive'
when gaia apps do reader.openSession(); but when apps perform session.OpenLogicalChannel() , set this
to true.  Also readers.close() should close all readers and descendent Session and Channel objects.
@@ +76,5 @@
> +};
> +
> +[JSImplementation="@mozilla.org/secureelement/SEChannel;1"]
> +interface MozSEChannel {
> +

>> you don't have isClosed().

I think we will maintain an internal state of SEChannel (whether it is 'closed' or 'active' etc..)
Do you think there is a need to expose it to App users ?


@@ +78,5 @@
> +[JSImplementation="@mozilla.org/secureelement/SEChannel;1"]
> +interface MozSEChannel {
> +
> +  // Handle of current channel that represents a logical connection with the SE
> +  readonly attribute long channel;


 >> Is this a channel ID?
>>
>> Why do web apps needs to know the channelId given that we already have a MozSEChannel object?
>> Also why doesn't other objects like Reader, Session doesn't have a 'id'?

Yes this is handle to channel. I think we can remove this and keep it an internal value only.



@@ +87,5 @@
> +   * @param apdu
> +   *     MozSECommand to be sent to secure element
> +   *
> +   * @return If success, the promise is resolved with the new created
> +   * MozSEResponse object. Otherwise, rejected with an error.


>> Can't MozSEResponse be used for error?

As Ming already told, this is more SE API specific error being returned to the apps.
Also I made a slight modification to the comments to be explicit


@@ +114,5 @@
> +  attribute unsigned short  le;     // The length of the expected
> +                                    // response data or -1 if none is expected - len
> +};
> +
> +[Constructor(Uint8Array data)]

>> When wll this cstor be used?
When Gecko receives a Response Apdu ('data') to say, transmit() command (its equivalent on baseband cmd is AT+CSIM)
we will have to perform somthing like below
sw1 = 0x00FF & data[data.length - 2];
sw2 = 0x00FF & data[data.length - 1];
So sw1 & sw2 will be filled up subsequently in the constructor function of SEResponse object


@@ +27,5 @@
> +   * @return If success, the promise is resolved with the new created
> +   * MozSEReader object of requested type. Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReader>
> +  Promise getSEReader(SEType seType);


>> This interface totally looks useless to me.
>> How does web app know what seType are supported?
One way , with existing API proposals is to do the following
 arrReaders[] = mozSEMgr.getSEReaders() or use mozSEMgr.getSEReader('type') if one wants to know if SE is present for a specific type
  arrReaders[0] // say is UICC
  arrReaders[1] // say is eSE
arrReaders[0].isSEPresent will tell the apps. Moreover this boolean state will also indicate the right values given the removable nature of some SEs (such as UICC or sdCard)
 if UICC is removed, 'isSEPresent' will be false

>> Doesn't it still need to call getSEReaders() to enumerate all the readers?
>> Then it could just get the reader in the array, why does it still need to call this API?
getSEReader() is just a helper API (easy to use one). If certain Gaia Wallet app of MNO's is being written, it may not be interested to enumerate on eSE 
In that case, it may simply use
uiccReader = mozSEMgr.getSEReader('uicc');

>> Unless you forgot to add a method 'getSupportedSETypes()',
>> but still, getSEReaders seems enough for us.
If you think 'getSupportedSETypes()' is needed, I will go ahead and add but as said above, apps can still know if the support exists or not by using
arrReaders[$index].isSEPresent.

>>I have second thoughts,
>>we might not need these two callbacks in the first draft, 
Yes agreed.
Attachment #8438779 - Attachment is obsolete: true
Attachment #8440341 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 56

3 years ago
Created attachment 8440342 [details] [diff] [review]
(v1.3) Secure Element APIs - Inital Draft
Attachment #8440341 - Attachment is obsolete: true
Attachment #8440341 - Flags: feedback?(allstars.chh)
Attachment #8440342 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 57

3 years ago
Created attachment 8440343 [details] [diff] [review]
(v1.3) Secure Element APIs - Inital Draft
Attachment #8440342 - Attachment is obsolete: true
Attachment #8440342 - Flags: feedback?(allstars.chh)
Attachment #8440343 - Flags: feedback?(allstars.chh)
(In reply to Siddartha P from comment #55)
> Created attachment 8440341 [details] [diff] [review]
> (v1.3) Secure Element APIs - Inital Draft
> 
> 
> @@ +32,5 @@
> > +[JSImplementation="@mozilla.org/secureelement/SESession;1"]
> > +interface MozSESession {
> > +
> > +  // Status of current session
> > +  readonly attribute boolean isActive;
> 
> >> When will it be 'inactive'?
> >> Or this variable will be false when we call reader.close() ?
> >> then it seems 'isClosed' is more appropriate.
> 
> Yes the reader.close(), the boolean 'isActive' flag will be set to false.
> Typically a reader may have several opened sessions. Intent was to have this
> flag set to 'inactive'
> when gaia apps do reader.openSession(); but when apps perform
> session.OpenLogicalChannel() , set this
> to true.  Also readers.close() should close all readers and descendent
> Session and Channel objects.

Why don't we call it isClosed() to make it more clear? 
 
> @@ +76,5 @@
> > +};
> > +
> > +[JSImplementation="@mozilla.org/secureelement/SEChannel;1"]
> > +interface MozSEChannel {
> > +
> 
> >> you don't have isClosed().
> 
> I think we will maintain an internal state of SEChannel (whether it is
> 'closed' or 'active' etc..)
> Do you think there is a need to expose it to App users ?
> 
Yes,
otherwise why there's is isClosed for Session however there's no isClosed() for Channel?
 
> @@ +87,5 @@
> > +   * @param apdu
> > +   *     MozSECommand to be sent to secure element
> > +   *
> > +   * @return If success, the promise is resolved with the new created
> > +   * MozSEResponse object. Otherwise, rejected with an error.
> 
> 
> > +
> > +[Constructor(Uint8Array data)]
> 
> >> When wll this cstor be used?
> When Gecko receives a Response Apdu ('data') to say, transmit() command (its
> equivalent on baseband cmd is AT+CSIM)
> we will have to perform somthing like below
> sw1 = 0x00FF & data[data.length - 2];
> sw2 = 0x00FF & data[data.length - 1];
> So sw1 & sw2 will be filled up subsequently in the constructor function of
> SEResponse object

Why can't we have something like 
Constructor(octet sw1, octet sw2, Uint8Array data)
 
> 
> @@ +27,5 @@
> > +   * @return If success, the promise is resolved with the new created
> > +   * MozSEReader object of requested type. Otherwise, rejected with an error.
> > +   */
> > +  // Promise<MozSEReader>
> > +  Promise getSEReader(SEType seType);
> 
> 
> >> This interface totally looks useless to me.
> >> How does web app know what seType are supported?
> One way , with existing API proposals is to do the following
>  arrReaders[] = mozSEMgr.getSEReaders() or use mozSEMgr.getSEReader('type')
> if one wants to know if SE is present for a specific type
>   arrReaders[0] // say is UICC
>   arrReaders[1] // say is eSE
> arrReaders[0].isSEPresent will tell the apps. Moreover this boolean state
> will also indicate the right values given the removable nature of some SEs
> (such as UICC or sdCard)
>  if UICC is removed, 'isSEPresent' will be false
> 
I don't think you answer the question.
To me isSEPresenet is totally different from getSEReader()
You still get a SEReader even its SE is not present, right?

> >> Doesn't it still need to call getSEReaders() to enumerate all the readers?
> >> Then it could just get the reader in the array, why does it still need to call this API?
> getSEReader() is just a helper API (easy to use one). 
Yes, it's just a helper API and we could add it until we really need this, right now I think we should focus on the necessary interfaces first, also you didn't provide implementation for this.
I'll suggest you add this interface later and focus on what we should do in this first version first.
Attachment #8440343 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 59

3 years ago
Created attachment 8441580 [details] [diff] [review]
(v1.4) Secure Element APIs - Inital Draft
Attachment #8440343 - Attachment is obsolete: true
Attachment #8441580 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 60

3 years ago
>To me isSEPresenet is totally different from getSEReader()
Yes.True
>You still get a SEReader even its SE is not present, right?
Yes, Gaia apps still get a valid SEReader obj, with 'isSEPresent' to false.
Comment on attachment 8441580 [details] [diff] [review]
(v1.4) Secure Element APIs - Inital Draft

Review of attachment 8441580 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElementManager.webidl
@@ +18,5 @@
> +
> +[JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager",
> + Func="Navigator::HasSecureElementManagerSupport"]
> +interface MozSEManager : EventTarget {

Why does it inherit EventTarget?

@@ +33,5 @@
> +
> +// Mozilla Only
> +partial interface MozSEManager {
> +   [ChromeOnly]
> +   void eventListenerWasAdded(DOMString aType);

What event will be listened?
Attachment #8441580 - Flags: feedback?(allstars.chh)

Comment 62

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #61)
> Comment on attachment 8441580 [details] [diff] [review]

> What event will be listened?

Possibly an artifact of Bug 979767, which was moved to mozNfc. Sid?

Comment 63

3 years ago
At least the onsepresent and onseremoval events, which we are going to support in the 2nd. phase.
Also please also file the follow-up bugs for the CE-API and SE-routing so we can discuss next week.
(Assignee)

Comment 65

3 years ago
Created attachment 8444259 [details] [diff] [review]
(v1.5) Secure Element APIs - Inital Draft

Removed EventTarget from MozSEManager interface
Attachment #8441580 - Attachment is obsolete: true
Attachment #8444259 - Flags: review?(allstars.chh)
Comment on attachment 8444259 [details] [diff] [review]
(v1.5) Secure Element APIs - Inital Draft

Review of attachment 8444259 [details] [diff] [review]:
-----------------------------------------------------------------

This patch doesn't have implementation yet so I only feedback+ on this.

Also please send your draft to dev-webapi.
Attachment #8444259 - Flags: review?(allstars.chh) → feedback+
No longer blocks: 979767
no longer block bug 979767 per scoping discussion
Comment on attachment 8444259 [details] [diff] [review]
(v1.5) Secure Element APIs - Inital Draft

Review of attachment 8444259 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElement.webidl
@@ +103,5 @@
> +};
> +
> +// Interface that represents an APDU command to be sent to a secure element.
> +[Constructor(octet data, octet ins, octet p1, octet p2, optional ArrayBufferView data, optional octet le)]
> +interface MozSECommand {

This command is from ISO 7816-4, http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4.aspx
Comment on attachment 8444259 [details] [diff] [review]
(v1.5) Secure Element APIs - Inital Draft

Review of attachment 8444259 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElement.webidl
@@ +90,5 @@
> +   * @return If success, the promise is resolved with the new created
> +   * MozSEResponse object. Otherwise, rejected with the error of type 'SEError'.
> +   */
> +  // Promise<MozSEResponse>
> +  Promise transmit(MozSECommand command);

Hi Sidd,

When you implement this IDL, please make sure that the values in 'command' are validated against the ISO spec. For security reasons, we cannot allow web apps to write directly to hardware devices without checking the input first.

Comment 70

3 years ago
According to the OpenMobileAPI specification, there are the following restrictions on the set of APDU commands that can be sent: 

   1) MANAGE_CHANNEL commands are not allowed. (see the link for the definition of MANAGE_CHANNEL commands: http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_6_basic_interindustry_commands.aspx#chap6_16)

   2) SELECT by DF Name (p1=04) are not allowed.  

   3) CLA bytes with channel numbers are de-masked.

Updated

3 years ago
Depends on: 1030602
Blocks: 1028094
Depends on: 1030615
Blocks: 1034533

Comment 71

3 years ago
Created attachment 8450965 [details]
FxOS_Payment_NFC_Handset_Architecture_v1.0.png
(In reply to Yoshi Huang[:allstars.chh] from comment #66)
> Comment on attachment 8444259 [details] [diff] [review]
> (v1.5) Secure Element APIs - Inital Draft
> 
> Review of attachment 8444259 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> This patch doesn't have implementation yet so I only feedback+ on this.
> 
> Also please send your draft to dev-webapi.

I forgot to mention please read the guide line below,
https://wiki.mozilla.org/WebAPI/ExposureGuidelines

This is the new rule since WebNFC has been landed.

Comment 73

3 years ago
(In reply to Ming Yin from comment #71)
> Created attachment 8450965 [details]
> FxOS_Payment_NFC_Handset_Architecture_v1.0.png

Thanks for this payment architecture. It is very clear. But I wonder if you could list the exact things that we need to do for ACE in Gecko. According to what we need to do for ACE, we can start to define internal interfaces between RIL and ACE as well.

Comment 74

3 years ago
(In reply to Ken Chang[:ken] from comment #73)
> (In reply to Ming Yin from comment #71)
> > Created attachment 8450965 [details]
> > FxOS_Payment_NFC_Handset_Architecture_v1.0.png
> 
> Thanks for this payment architecture. It is very clear. But I wonder if you
> could list the exact things that we need to do for ACE in Gecko. According
> to what we need to do for ACE, we can start to define internal interfaces
> between RIL and ACE as well.


Please find the SE cccess Control archtiecture diagram under https://bug884594.bugzilla.mozilla.org/attachment.cgi?id=8378229

and the SE Access Control Enforcement workflow under https://bug884594.bugzilla.mozilla.org/attachment.cgi?id=8378230

Both diagrams follow the same principle defined in GlobalPlatform SE Access Control Specification v1.0
https://drive.google.com/file/d/0B6i9bmS3lyFrLTgtTUJaZ1ZwT3M/edit?usp=sharing


Regarding the generic SIM access interface between SE and RIL, I believe, it depends on OEM. I don't think there is any standard for it.  But, we don't have a list of requirements for RIL and baseband in terms of supporting the APDU-based logcial channel communication between web apps and SE/SIM applets.

Comment 75

3 years ago
(In reply to Ming Yin from comment #74)
> (In reply to Ken Chang[:ken] from comment #73)
> > (In reply to Ming Yin from comment #71)
> > > Created attachment 8450965 [details]
> > > FxOS_Payment_NFC_Handset_Architecture_v1.0.png
> > 
> > Thanks for this payment architecture. It is very clear. But I wonder if you
> > could list the exact things that we need to do for ACE in Gecko. According
> > to what we need to do for ACE, we can start to define internal interfaces
> > between RIL and ACE as well.
> 
> 
> Please find the SE cccess Control archtiecture diagram under
> https://bug884594.bugzilla.mozilla.org/attachment.cgi?id=8378229
> 
> and the SE Access Control Enforcement workflow under
> https://bug884594.bugzilla.mozilla.org/attachment.cgi?id=8378230
> 
> Both diagrams follow the same principle defined in GlobalPlatform SE Access
> Control Specification v1.0
> https://drive.google.com/file/d/0B6i9bmS3lyFrLTgtTUJaZ1ZwT3M/edit?usp=sharing
> 
> 
> Regarding the generic SIM access interface between SE and RIL, I believe, it
> depends on OEM. I don't think there is any standard for it.  But, we don't
> have a list of requirements for RIL and baseband in terms of supporting the
> APDU-based logcial channel communication between web apps and SE/SIM applets.


Ken, sorry, one correction to my last comment.
 
We do have a list of requirements for RIL vendor to support the APDU-based logcial channel communication between web apps and SE/SIM applets.

1) Extension of RIL Lib and its interface
The RIL library shall provide functionality to support logical channels so that the trusted Gaia applications can communicate with a specific Java Card Applet installed on the SIM card and identified by its AID.  
3 new function calls are expected:
- Open a logical channel
- Exchange APDU 
- Close a logical channel


2) Extensions of baseband processor
Baseband processor shall support a list of AT commands as defined by 3GPP TS 27.007 specification. 
4 AT commands are expected:
- AT+CSIM  (Access to SIM)
- AT+CCHO  (Open Logical Channel)
- AT+CCHC  (Close Logical Channel)
- AT+CGLA (Generic UICC Logical Channel Access)
Comment on attachment 8444259 [details] [diff] [review]
(v1.5) Secure Element APIs - Inital Draft

I'm going to review the API next week.
Attachment #8444259 - Flags: feedback?(ehsan)

Comment 77

3 years ago
Created attachment 8456179 [details]
SE-Access-Architecture_step-1.png
Comment on attachment 8444259 [details] [diff] [review]
(v1.5) Secure Element APIs - Inital Draft

Review of attachment 8444259 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElement.webidl
@@ +1,5 @@
> +/* This Source Code Form is subject to the terms of the Mozilla Public
> + * License, v. 2.0. If a copy of the MPL was not distributed with this
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +[JSImplementation="@mozilla.org/secureelement/SEReader;1"]

What kinds of apps is this going to be exposed to?  Please use [AvailableIn] or [CheckPermission] as appropriate.  Same for other interfaces defined in this file.

@@ +2,5 @@
> + * License, v. 2.0. If a copy of the MPL was not distributed with this
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +[JSImplementation="@mozilla.org/secureelement/SEReader;1"]
> +interface MozSEReader {

Please don't use Moz prefixes.

@@ +22,5 @@
> +
> +  /**
> +   * Closes all sessions associated with this Reader and its associated channels.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .

Why do you need to resolve the promise to the MozSEReader when the caller presumably had access to the MozSEReader instance so that they would be able to call close?

@@ +25,5 @@
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .
> +   */
> +  // Promise<MozSEReader>
> +  Promise close();

Call this closeAll perhaps?

@@ +29,5 @@
> +  Promise close();
> +};
> +
> +[JSImplementation="@mozilla.org/secureelement/SESession;1"]
> +interface MozSESession {

Nit: I think our build system expects each interface to go into its own .webidl file.

@@ +34,5 @@
> +
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided

This property is not nullable...

@@ +35,5 @@
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided
> +  readonly attribute octet[] atr;

Why are you using cotet[] here and below?  I think we should use TypedArrays here.

@@ +59,5 @@
> +   * @return If the operation is successful the promise is resolved with an instance of MozSEChannel.
> +   * NOTE: Some secure elements may deny opening a basic channel. In such a scenario, promise is resolved with SEIoError.
> +   */
> +  // Promise<MozSEChannel>
> +  Promise openBasicChannel(octet[] aid);

What is the difference between a basic channel and a logical channel?  The difference should be explained in the prose.

@@ +65,5 @@
> +  /**
> +   * Closes the active communication channel to the application on Secure Element. This will also
> +   * close all other active channels associated with this session.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSESession object that is closed.

Why do you need to resolve the promise to the MozSESession?

@@ +78,5 @@
> +  // Status of channel
> +  readonly attribute boolean isClosed;
> +
> +  // Is it a basic channel ?
> +  readonly attribute boolean isBasicChannel;

Should we instead do:

enum SEChannelType { "basic", "logical" };

readonly attribute SEChannelType type;

@@ +90,5 @@
> +   * @return If success, the promise is resolved with the new created
> +   * MozSEResponse object. Otherwise, rejected with the error of type 'SEError'.
> +   */
> +  // Promise<MozSEResponse>
> +  Promise transmit(MozSECommand command);

You should probably specify when the contents of |command| are read.  For example, what is the effect of this code?

  var cmd = new MozSECommand(...);
  channel.transmit(cmd);
  cmd.ins++;

@@ +95,5 @@
> +
> +  /**
> +   * Closes the active channel.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEChannel object that is closed.

Again, why?

@@ +102,5 @@
> +  Promise close();
> +};
> +
> +// Interface that represents an APDU command to be sent to a secure element.
> +[Constructor(octet data, octet ins, octet p1, octet p2, optional ArrayBufferView data, optional octet le)]

Do these two optionals have default values?  If no, you may want to make the corresponding attributes nullable.

@@ +105,5 @@
> +// Interface that represents an APDU command to be sent to a secure element.
> +[Constructor(octet data, octet ins, octet p1, octet p2, optional ArrayBufferView data, optional octet le)]
> +interface MozSECommand {
> +
> +  attribute octet           cla;    // 1 Byte  : Class Byte

Does this map to the first |data| in the constructor?  If yes, please rename that to cla.  At any rate, you shouldn't reuse those names!

@@ +114,5 @@
> +  attribute unsigned short  le;     // The length of the expected
> +                                    // response data or -1 if none is expected - len
> +};
> +
> +[Constructor(octet sw1, octet sw2, Uint8Array data)]

Are you sure that you want a Uint8Array here and not a view?

Also, why is it useful for this interface to have a constructor?

::: dom/webidl/MozSecureElementManager.webidl
@@ +13,5 @@
> +  "SEBadStateError",            // Error occuring as a result of bad state.
> +  "SEInvalidChannelError,       // Opening a channel failed because no channel is available.
> +  "SEInvalidApplicationError",  // The requested application was not found on the secure element.
> +  "SEGenericError"              // Generic failures.
> +};

It would be nice if you could move these enums to the other webidl file.

@@ +17,5 @@
> +};
> +
> +[JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager",
> + Func="Navigator::HasSecureElementManagerSupport"]

What is this function supposed to check?

@@ +26,5 @@
> +   *
> +   * @return If success, the promise is resolved to  an array of instances
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReaders>

Did you mean MozSEReader here?  Or is there an interface missing from these WebIDL files?

@@ +27,5 @@
> +   * @return If success, the promise is resolved to  an array of instances
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReaders>
> +  Promise getSEReaders();

Why not move getSEReaders on Navigator and remove MozSEManager?
Attachment #8444259 - Flags: feedback?(ehsan) → feedback-
Blocks: 1044428
No longer blocks: 860906
(Assignee)

Comment 79

3 years ago
Created attachment 8465143 [details] [diff] [review]
(v1.6) Secure Element APIs - Inital Draft

Hi Ehsan,
Sorry, I was late in responding to your feedback. I noticed your comments much later. I have uploaded another patch for your review.
I have addressed most of your comments except couple of them maybe. 

Yoshi, I have also added you to provide your feedback as well as you were the original reviewer.
Attachment #8444259 - Attachment is obsolete: true
Attachment #8465143 - Flags: feedback?(ehsan)
Attachment #8465143 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 80

3 years ago
Comment on attachment 8444259 [details] [diff] [review] [diff] [review]
(v1.5) Secure Element APIs - Inital Draft

Review of attachment 8444259 [details] [diff] [review] [diff] [review]:
-----------------------------------------------------------------


> +[JSImplementation="@mozilla.org/secureelement/SEReader;1"]

>> What kinds of apps is this going to be exposed to?  Please use [AvailableIn] or [CheckPermission] as appropriate.  Same for other interfaces defined in this file.

Applications such as Payment, Couponing, Ticketing, loyalty cards that wish to avail secure element on UICC or emebedded chip will use these interfaces. These applications should be certified / privileged only. We are proposing to introduce the permission 'secureelement-manage' (available to only certified & privileged). Added [AvailableIn] keyword twice , one for certified and another for privileged.


> +[JSImplementation="@mozilla.org/secureelement/SEReader;1"]
> +interface MozSEReader {

>> Please don't use Moz prefixes.

Ok. Any reasons why 'Moz' should not be using as a prefix.

@@ +22,5 @@
> +
> +  /**
> +   * Closes all sessions associated with this Reader and its associated channels.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .


>> Why do you need to resolve the promise to the MozSEReader when the caller presumably had access to the MozSEReader instance so that they would be able to call close?
The first part (Why resolved to 'MozSEReader') of question is answered @ [1].

Second question is what if apps directly instantiate 'MozSEReader' and call close() ?
I thought the answer to the second part lies in the implementation details of 'MozSEReader' and other objects' JS implementation. Say, In the implementation of MozSEReader object, by not exposing 'init()' .  By ensuring this way Gaia apps may not be able to instantiate using something like var reader = window.navigator.mozSEReader; 
What do you  think? Please suggest if thats not the case.

@@ +25,5 @@
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .
> +   */
> +  // Promise<MozSEReader>
> +  Promise close();


>> Call this closeAll perhaps?
 
Maybe 'close()' seems to be ok to me. A SEReader object may have multiple opened sessions (SESession), which may in turn have several opened channels (SEChannel) . 
Each interface object has an associated  close () method to release all resources associated to the object, and also triggers close() method on all underlying objects that it owns down its chain.
What do you think ?

@@ +29,5 @@
> +  Promise close();
> +};
> +
> +[JSImplementation="@mozilla.org/secureelement/SESession;1"]
> +interface MozSESession {


>> Nit: I think our build system expects each interface to go into its own .webidl file.

Actually I was able to compile with multiple interfaces in one webidl file.

@@ +34,5 @@
> +
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided


>> This property is not nullable...

I had compile issues with 'octet[]'. Instead , I have now changed this type to
[Cached, Pure] readonly attribute sequence<octet> atr;  . Is this property nullable ? Please suggest.

@@ +35,5 @@
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided
> +  readonly attribute octet[] atr;


>> Why are you using cotet[] here and below?  I think we should use TypedArrays here.
Ok. Agreed. Do you think "[Cached, Pure] readonly attribute sequence<octet> atr;" would suffice here ? 
I couldn't use Uint8Array as this typed array is not implemented for JS. It gave me compile errors, however sequence of octets did not give one. I also had to prefix the attribute 'cached' as compiler
was forcing me to add one to sequence attributes.

@@ +59,5 @@
> +   * @return If the operation is successful the promise is resolved with an instance of MozSEChannel.
> +   * NOTE: Some secure elements may deny opening a basic channel. In such a scenario, promise is resolved with SEIoError.
> +   */
> +  // Promise<MozSEChannel>
> +  Promise openBasicChannel(octet[] aid);


>> What is the difference between a basic channel and a logical channel?  The difference should be explained in the prose.

Ok. Added the key difference (mainly for security reasons on an UICC card, generally access to basic channel is disallowed.) between basic & logical channels @ openBasicChannel(..) & openLogicalChannel(..) respectively.


@@ +65,5 @@
> +  /**
> +   * Closes the active communication channel to the application on Secure Element. This will also
> +   * close all other active channels associated with this session.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSESession object that is closed.


>> Why do you need to resolve the promise to the MozSESession?
Please review my answer provided @ [1].

@@ +78,5 @@
> +  // Status of channel
> +  readonly attribute boolean isClosed;
> +
> +  // Is it a basic channel ?
> +  readonly attribute boolean isBasicChannel;


>> Should we instead do:
>> enum SEChannelType { "basic", "logical" };
>> readonly attribute SEChannelType type;
Ok.

@@ +90,5 @@
> +   * @return If success, the promise is resolved with the new created
> +   * MozSEResponse object. Otherwise, rejected with the error of type 'SEError'.
> +   */
> +  // Promise<MozSEResponse>
> +  Promise transmit(MozSECommand command);


>> You should probably specify when the contents of |command| are read.  For example, what is the effect of this code?
>>  var cmd = new MozSECommand(...);
>>  channel.transmit(cmd);
>>  cmd.ins++;
I think, when Gaia apps call transmit(cmd), the  'cmd' details would be sent over socket to ril daemon (in case of UICC) and the contents are then subsequently transmitted transparently
to the baseband as one atomic operation. The response of this operation is abstracted in the object 'MozSEResponse'. Upon further modification of the 'cmd' details (cmd.ins++), no further effect will occur. I added few notes on the need to synchronoize this command for the sake of clarity. Hope it helps.

@@ +95,5 @@
> +
> +  /**
> +   * Closes the active channel.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEChannel object that is closed.


>> Again, why?
*[1]
This is also the answer to one of your earlier questions (Why resolve to 'MozSEReader' & 'MozSESession' ?)
Here class relationships of various  secure element interfaces in MozSecureElement.webidl.
[Navigator]--> [MozSEManager]--> [MozSEReader]--> [MozSESession]--> [MozSEChannel]
           0-1               0-n              0-n               0-n
MozSEChannel represents an object that provides access to Gaia apps to send APDU commands using 'transmit()' API. This object also indicates the type of channel it is.
By designing APIs this way, Gaia apps can nicely chain the functionality

---------------------------------------------------------------------------------
var mastercardAid = [0, 1, 2, 3];

var getUiccReader = function(readers) {
    var uiccReader = readers.filter(function (reader) {
        return reader.type === 'uicc';
    })[0];
    
    if (!uiccReader) {
        throw new Error('No UICC SE reader found.');
    }
    
    return uiccReader;
};

var SEManager = navigator.mozSecureElement;
if (!SEManager) {
   // Error Msg
}

SEManager.getSEReaders()
         .then(getUiccReader)
         .then(function(reader) {
             return reader.openSession();
         })
         .then(function(session) {
             return session.openLogicalChannel(mastercardAid);
         })
         .then(function (channel) {
             // Some values here.
             var command = new MozSECommand(0, 0, 0, 0, [], 10);
             return channel.transmit(command);
         })
         .then(function (response) {
             console.log('Received from applet:', response.data);
         })
         // TODO: close and cleanup
         .catch(function (err) {
             console.error('Could not communicate with applet:', err);
         });
---------------------------------------------------------------------------------

@@ +102,5 @@
> +  Promise close();
> +};
> +
> +// Interface that represents an APDU command to be sent to a secure element.
> +[Constructor(octet data, octet ins, octet p1, octet p2, optional ArrayBufferView data, optional octet le)]


>> Do these two optionals have default values?  If no, you may want to make the corresponding attributes nullable.
Ok. Done.


@@ +105,5 @@
> +// Interface that represents an APDU command to be sent to a secure element.
> +[Constructor(octet data, octet ins, octet p1, octet p2, optional ArrayBufferView data, optional octet le)]
> +interface MozSECommand {
> +
> +  attribute octet           cla;    // 1 Byte  : Class Byte


>> Does this map to the first |data| in the constructor?  If yes, please rename that to cla.  At any rate, you shouldn't reuse those names!
Ok. corrected.

@@ +114,5 @@
> +  attribute unsigned short  le;     // The length of the expected
> +                                    // response data or -1 if none is expected - len
> +};
> +
> +[Constructor(octet sw1, octet sw2, Uint8Array data)]


>> Are you sure that you want a Uint8Array here and not a view?
In latest version of webidl, I have removed 'Uint8Array' ,instead used sequnce of octets.

>> Also, why is it useful for this interface to have a constructor?

> When Gecko receives a Response Apdu ('data') to say, an earlier 'transmit()' command (its equivalent on the baseband cmd is AT+CSIM)
> we may have to do something like this
> sw1 = 0x00FF & data[data.length - 2];
> sw2 = 0x00FF & data[data.length - 1];
> So sw1 & sw2 will be filled up subsequently in the constructor function of SEResponse object


::: dom/webidl/MozSecureElementManager.webidl
@@ +13,5 @@
> +  "SEBadStateError",            // Error occuring as a result of bad state.
> +  "SEInvalidChannelError,       // Opening a channel failed because no channel is available.
> +  "SEInvalidApplicationError",  // The requested application was not found on the secure element.
> +  "SEGenericError"              // Generic failures.
> +};


>> It would be nice if you could move these enums to the other webidl file.
Ok. done!

@@ +17,5 @@
> +};
> +
> +[JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager",
> + Func="Navigator::HasSecureElementManagerSupport"]

>> What is this function supposed to check?
This is a utility/helper function implemented in Navigator.cpp. It will check if the current device / FFOS builds have 'SecureElement' support or not.
There are few such HasXXXSupport helper functions in Navigator.cpp.

@@ +26,5 @@
> +   *
> +   * @return If success, the promise is resolved to  an array of instances
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReaders>


>> Did you mean MozSEReader here?  Or is there an interface missing from these WebIDL files?
Corrected!

@@ +27,5 @@
> +   * @return If success, the promise is resolved to  an array of instances
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReaders>
> +  Promise getSEReaders();


> Why not move getSEReaders on Navigator and remove MozSEManager?
MozSecureElementManager.webidl currently exposes only one API and provides the basic access to underlying to secure element h/w.
However in future there will be a need to add new APIs and support 'Card Emulation modes' etc. In the initial draft these APIs have been 
deliberately omitted.
Comment on attachment 8465143 [details] [diff] [review]
(v1.6) Secure Element APIs - Inital Draft

Review of attachment 8465143 [details] [diff] [review]:
-----------------------------------------------------------------

eshan's feedback is enough.
Attachment #8465143 - Flags: feedback?(allstars.chh)
Comment on attachment 8465143 [details] [diff] [review]
(v1.6) Secure Element APIs - Inital Draft

Review of attachment 8465143 [details] [diff] [review]:
-----------------------------------------------------------------

I'm repeating all of the questions I asked before which are not answered yet.  Please address all of them in the next iteration, I don't want to keep copy and pasting my previous comments.  :-)

::: dom/webidl/MozSecureElement.webidl
@@ +21,5 @@
> +  "logical"
> +};
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

You don't need to mention certified apps.  Anything that is available in privileged apps will be available to certified apps as well.

@@ +24,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SEReader;1"]
> +interface MozSEReader {

Repeat: Please don't use Moz prefixes.

@@ +45,5 @@
> +
> +  /**
> +   * Closes all sessions associated with this Reader and its associated channels.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .

Repeat: Why do you need to resolve the promise to the MozSEReader when the caller presumably had access to the MozSEReader instance so that they would be able to call close?

@@ +49,5 @@
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .
> +   */
> +  // Promise<MozSEReader>
> +  [Throws]
> +  Promise close();

Repeat: Call this closeAll perhaps?

@@ +53,5 @@
> +  Promise close();
> +};
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

Ditto.

@@ +56,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SESession;1"]
> +interface MozSESession {

Repeat: Nit: I think our build system expects each interface to go into its own .webidl file.

@@ +61,5 @@
> +
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided

Repeat: This property is not nullable...

@@ +62,5 @@
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided
> +  [Cached, Pure] readonly attribute sequence<octet> atr;

Why does this need to be [Cached, Pure]?

@@ +98,5 @@
> +  /**
> +   * Closes the active communication channel to the application on Secure Element. This will also
> +   * close all other active channels associated with this session.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSESession object that is closed.

Repeat: Why do you need to resolve the promise to the MozSESession?

@@ +106,5 @@
> +  Promise close();
> +};
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

Same.

@@ +130,5 @@
> +   * MozSEResponse object. Otherwise, rejected with the error of type 'SEError'.
> +   */
> +  // Promise<MozSEResponse>
> +  [Throws]
> +  Promise transmit(MozSECommand command);

Repeat: You should probably specify when the contents of |command| are read. For example, what is the effect of this code?
var cmd = new MozSECommand(...);
channel.transmit(cmd);
cmd.ins++;

@@ +135,5 @@
> +
> +  /**
> +   * Closes the active channel.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEChannel object that is closed.

Repeat: Again, why?

@@ +144,5 @@
> +};
> +
> +// Interface that represents an APDU command to be sent to a secure element.
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

And here.

@@ +147,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SECommand;1",
> + Constructor(octet cla, octet ins, octet p1, octet p2, optional sequence<octet>? data = null, optional short le= -1)]

Why did you switch away from using a typed array here?

@@ +154,5 @@
> +  attribute octet            cla;    // 1 Byte  : Class Byte
> +  attribute octet            ins;    // 1 Byte  : Instruction Byte
> +  attribute octet            p1;     // 1 Byte  : First Octet of Parameters Byte
> +  attribute octet            p2;     // 1 Byte  : Second Octet of Parameters Byte
> +  [Cached, Pure] attribute sequence<octet>  data;   // Sequence of octets

Why did you switch away from using a typed array here?

@@ +160,5 @@
> +                                     // response data or -1 if none is expected
> +};
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

Here too.

@@ +163,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SEResponse;1",
> + Constructor(octet sw1, octet sw2, sequence<octet> data)]

typed array...

Also, repeat: Also, why is it useful for this interface to have a constructor?

@@ +173,5 @@
> +  // Second octet of response's status word
> +  readonly attribute octet        sw2;
> +
> +  // The response's data field bytes
> +  [Cached, Pure] readonly attribute sequence<octet>  data;

here too.

::: dom/webidl/MozSecureElementManager.webidl
@@ +3,5 @@
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +[JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager",
> + Func="Navigator::HasSecureElementManagerSupport"]

Repeated question: What is this function supposed to check?

@@ +12,5 @@
> +   *
> +   * @return If success, the promise is resolved to  an array of instances
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReader[]>

You probably want Promise<sequence<MozSEReader>> instead, see http://heycam.github.io/webidl/#idl-sequence.

@@ +14,5 @@
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReader[]>
> +  [Throws]
> +  Promise getSEReaders();

Repeated question: Why not move getSEReaders on Navigator and remove MozSEManager?
Attachment #8465143 - Flags: feedback?(ehsan) → feedback-
(Assignee)

Comment 83

3 years ago
Comment on attachment 8465143 [details] [diff] [review]
(v1.6) Secure Element APIs - Inital Draft

Review of attachment 8465143 [details] [diff] [review]:
-----------------------------------------------------------------

Thanks for your feedback. I have mostly addressed your earlier comments in comments#80 , comments#79. Unfortunately, I have not commented inline as I am doing it now. Sorry about that though!

::: dom/webidl/MozSecureElement.webidl
@@ +21,5 @@
> +  "logical"
> +};
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

Ok. Will correct this in the next iteration.

@@ +24,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SEReader;1"]
> +interface MozSEReader {

From comment#80, 
"Ok. Any reasons why 'Moz' should not be using as a prefix."

Only reason to ask this question is to understand which interfaces are deemed to be 'moz' prefixed. This will also help us in rightly naming some of interfaces in future as well.

@@ +45,5 @@
> +
> +  /**
> +   * Closes all sessions associated with this Reader and its associated channels.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .

From Comment#80,

The first part (Why resolved to 'MozSEReader') of question is answered below [1]. All similar questions , such as, "why resolved to 'MozSExxx'?" have been answered at one place below.

Second question : What if apps directly instantiate 'MozSEReader' and call close() ?
I thought the answer to the second part lies in the implementation details of 'MozSEReader' and other objects' JS implementation. Say, In the implementation of MozSEReader object, by not exposing 'init()' .  By ensuring this way Gaia apps may not be able to instantiate using something like var reader = window.navigator.mozSEReader; 
What do you  think? Please suggest if that's not the case.

@@ +49,5 @@
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .
> +   */
> +  // Promise<MozSEReader>
> +  [Throws]
> +  Promise close();

From Comment#80,

Maybe 'close()' seems to be ok to me. A SEReader object may have multiple opened sessions (SESession), which may in turn have several opened channels (SEChannel) . Each interface object has an associated  close () method to release all resources associated to the object, and also triggers close() method on all underlying objects that it owns down its chain. 
What do you think ?

@@ +53,5 @@
> +  Promise close();
> +};
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

Ok. will fix this in the next iteration.

@@ +56,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SESession;1"]
> +interface MozSESession {

From Comment#80, 

Actually I was able to compile with multiple interfaces in one webidl file. 

The webidl's submitted for your feedback are compiled on FxOS builds. Gaia demo app is able to make use of the interfaces.

@@ +61,5 @@
> +
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided

From Comment#80,

I had compile issues with 'octet[]'. Instead , I have now changed this type to
[Cached, Pure] readonly attribute sequence<octet> atr;

* In the next iteration I will fix the comment (Remove: 'null if not provided')

@@ +62,5 @@
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided
> +  [Cached, Pure] readonly attribute sequence<octet> atr;

From Comment#80

I had to prefix the attribute 'cached' as compiler was forcing me to add one to sequence attributes (From MDN, "This can be used to implement attributes whose value is a sequence or dictionary , which would otherwise end up returning a new object each time and hence not be allowed in WebIDL").

Added 'Pure' since the attribute may have to return the same value.

@@ +98,5 @@
> +  /**
> +   * Closes the active communication channel to the application on Secure Element. This will also
> +   * close all other active channels associated with this session.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSESession object that is closed.

From comment#80

[1] Answering all questions on why promises should resolve to 'MozSExxx'.

Following is my attempt to answer your concern / question.

Class relationships of various  secure element interfaces:
[Navigator]--> [MozSEManager]--> [MozSEReader]--> [MozSESession]--> [MozSEChannel]
           0-1               0-n              0-n               0-n
MozSEChannel represents an object that provides access to Gaia apps to send APDU commands using 'transmit()' API. This object also indicates the type of channel it is. 
By designing APIs this way, all the SecureElement functionality is abstracted in various interface objects which perform certain functionality. Also Gaia apps can nicely chain the functionality using something like below

---------------------------------------------------------------------------------
var mastercardAid = [0, 1, 2, 3];

var getUiccReader = function(readers) {
    var uiccReader = readers.filter(function (reader) {
        return reader.type === 'uicc';
    })[0];
    
    if (!uiccReader) {
        throw new Error('No UICC SE reader found.');
    }
    
    return uiccReader;
};

var SEManager = navigator.mozSecureElement;
if (!SEManager) {
   // Error Msg
}

SEManager.getSEReaders()
         .then(getUiccReader)
         .then(function(reader) {
             return reader.openSession();
         })
         .then(function(session) {
             return session.openLogicalChannel(mastercardAid);
         })
         .then(function (channel) {
             // Some values here.
             var command = new MozSECommand(0, 0, 0, 0, [], 10);
             return channel.transmit(command);
         })
         .then(function (response) {
             console.log('Received from applet:', response.data);
         })
         // TODO: close and cleanup
         .catch(function (err) {
             console.error('Could not communicate with applet:', err);
         });
---------------------------------------------------------------------------------
 
I hope I have addressed your concern.

@@ +106,5 @@
> +  Promise close();
> +};
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

Ok. Will fix this in the next iteration.

@@ +130,5 @@
> +   * MozSEResponse object. Otherwise, rejected with the error of type 'SEError'.
> +   */
> +  // Promise<MozSEResponse>
> +  [Throws]
> +  Promise transmit(MozSECommand command);

From Comment#80

I think, when Gaia apps call transmit(cmd), the  'cmd' details would be sent over socket to ril daemon (in case of UICC) and the contents are then subsequently transmitted transparently to the baseband as one atomic operation. 
The response of this operation is abstracted in the object 'MozSEResponse'. Upon further modification of the 'cmd' details (cmd.ins++), no further effect will occur. I think. I have added few notes (in webidl for 'transmit' API) about the need to synchronize this command for the sake of clarity. Did I address your question ? Please suggest.

@@ +135,5 @@
> +
> +  /**
> +   * Closes the active channel.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEChannel object that is closed.

Probably explained in the earlier answer of why we need to resolve promises to 'MozSExxx'.

@@ +144,5 @@
> +};
> +
> +// Interface that represents an APDU command to be sent to a secure element.
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

Ok. Will fix this in the next iteration.

@@ +147,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SECommand;1",
> + Constructor(octet cla, octet ins, octet p1, octet p2, optional sequence<octet>? data = null, optional short le= -1)]

From Comment#80,

I couldn't use Uint8Array as this typed array is not implemented for JS. (Current plan is to have corresponding JS implementation for SE interfaces in gecko.) It gave me compile errors (Possibly due to https://bugzilla.mozilla.org/show_bug.cgi?id=929609) , however sequence of octets did not give one. I also had to prefix the attribute 'cached & Pure' as compiler was forcing me to add one to sequence attributes (that it needs to be cached)

@@ +154,5 @@
> +  attribute octet            cla;    // 1 Byte  : Class Byte
> +  attribute octet            ins;    // 1 Byte  : Instruction Byte
> +  attribute octet            p1;     // 1 Byte  : First Octet of Parameters Byte
> +  attribute octet            p2;     // 1 Byte  : Second Octet of Parameters Byte
> +  [Cached, Pure] attribute sequence<octet>  data;   // Sequence of octets

Hopefully same earlier explanation would go here as well

@@ +160,5 @@
> +                                     // response data or -1 if none is expected
> +};
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",

Ok. Will fix this in the next iteration.

@@ +163,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SEResponse;1",
> + Constructor(octet sw1, octet sw2, sequence<octet> data)]

From Comment#80

When Gecko receives a Response Apdu ('data') to say, an earlier 'transmit()' command (its equivalent on the baseband cmd is AT+CSIM)
SE impl may have to do something like this
sw1 = 0x00FF & data[data.length - 2];
sw2 = 0x00FF & data[data.length - 1];
So sw1 & sw2 will be filled up subsequently in the constructor function of SEResponse object

This was my earlier answer, but on second thoughts we may not need a constructor for SEResponse obj. I will modify it in the next iteration.

@@ +173,5 @@
> +  // Second octet of response's status word
> +  readonly attribute octet        sw2;
> +
> +  // The response's data field bytes
> +  [Cached, Pure] readonly attribute sequence<octet>  data;

I think earlier explanation holds good here as well.

::: dom/webidl/MozSecureElementManager.webidl
@@ +3,5 @@
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +[JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager",
> + Func="Navigator::HasSecureElementManagerSupport"]

From Comment#80

This is a utility/helper function implemented in Navigator.cpp. It will check if the current device / FFOS builds have 'SecureElement' support or not. There are few such HasXXXSupport helper functions in Navigator.cpp.

@@ +12,5 @@
> +   *
> +   * @return If success, the promise is resolved to  an array of instances
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReader[]>

Ok. Will fix this in the next iteration.

@@ +14,5 @@
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReader[]>
> +  [Throws]
> +  Promise getSEReaders();

From Comment#80

MozSecureElementManager.webidl currently exposes only one API and provides the basic access to underlying to secure element h/w.
However in future there will be a need to add new APIs and support 'Card Emulation modes' etc. In the initial draft these APIs have been 
deliberately ommited.
Comment on attachment 8465143 [details] [diff] [review]
(v1.6) Secure Element APIs - Inital Draft

Review of attachment 8465143 [details] [diff] [review]:
-----------------------------------------------------------------

My apologies, I didn't see comment 80..  :/

::: dom/webidl/MozSecureElement.webidl
@@ +24,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SEReader;1"]
> +interface MozSEReader {

The short answer is that this is our new API exposure policy <https://wiki.mozilla.org/WebAPI/ExposureGuidelines>.

The longer answer is that over the years we have realized that these vendor prefixes don't really achieve much in terms of warning people about the usage of the vendor specific technologies that have prefixed names, and they cause a lot of issues when content starts to depend on them (which means that we can't remove the prefixes) and also when a feature gets adopted by different browsers (because using a different API name in that case would mean that the code written against the vendor-prefixed version of the API won't work against the "standard" implementation.  This is an interesting read on the topic if you're curious.  <https://hsivonen.fi/vendor-prefixes/>

@@ +45,5 @@
> +
> +  /**
> +   * Closes all sessions associated with this Reader and its associated channels.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .

Sorry, I'm not sure if I follow your thoughts on the second question here.

@@ +49,5 @@
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .
> +   */
> +  // Promise<MozSEReader>
> +  [Throws]
> +  Promise close();

What you describe makes sense from a semantic perspective, but I still think calling this method 'closeAll' makes it more obvious to know what the code using the API is doing without having to note the difference between whether 'close' is called on a SEReader or a SESession.

@@ +56,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SESession;1"]
> +interface MozSESession {

Hmm, ok... I don't really remember what the issue I was referring to is exactly, but as long as it works.  ;-)

@@ +61,5 @@
> +
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided

The reason is that WebIDL arrays are passed by reference, so for an array property, it's not clear if the property getter should return a new object every time, or a reference to the same object, and choosing the former behavior breaks things such as |obj.atr === obj.atr| etc...  So in our implementation we do support WebIDL array properties as long as they are Cached and Pure, because that gives somewhat sane semantics.  But that is not needed for sequences.

But more importantly, is there a good reason to not use a typed array here?

@@ +62,5 @@
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided
> +  [Cached, Pure] readonly attribute sequence<octet> atr;

Same thing as above.

@@ +98,5 @@
> +  /**
> +   * Closes the active communication channel to the application on Secure Element. This will also
> +   * close all other active channels associated with this session.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSESession object that is closed.

I think I understand all of the above, but that still doesn't answer my question.  My question was specifically about close methods.  You usually resolve a promise with the results of the operation, but I think the semantic result of a close operation is void.  Note that the caller of the close method knows which object they're calling close on by definition, so they can keep track of it if they choose to.

@@ +130,5 @@
> +   * MozSEResponse object. Otherwise, rejected with the error of type 'SEError'.
> +   */
> +  // Promise<MozSEResponse>
> +  [Throws]
> +  Promise transmit(MozSECommand command);

OK, this makes sense.  So we basically copy the contents of the arguments when you call transmit.  Please update the prose to reflect this.  Thanks!

@@ +147,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SECommand;1",
> + Constructor(octet cla, octet ins, octet p1, octet p2, optional sequence<octet>? data = null, optional short le= -1)]

I would much rather see if we can fix bug 929609 instead of hacking the API to match our implementation bugs.  :-)

@@ +163,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SEResponse;1",
> + Constructor(octet sw1, octet sw2, sequence<octet> data)]

Hmm, I may not understand this part correctly.  Where do you get the SEResponse objects from in the first place?

::: dom/webidl/MozSecureElementManager.webidl
@@ +3,5 @@
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +[JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager",
> + Func="Navigator::HasSecureElementManagerSupport"]

But what are those checks exactly?

@@ +14,5 @@
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReader[]>
> +  [Throws]
> +  Promise getSEReaders();

OK, sounds good.
(Assignee)

Comment 85

3 years ago
Comment on attachment 8465143 [details] [diff] [review]
(v1.6) Secure Element APIs - Inital Draft

Review of attachment 8465143 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElement.webidl
@@ +24,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SEReader;1"]
> +interface MozSEReader {

Thanks for the explanation and sharing the link.
I have removed 'Moz' prefix in the latest patch.

@@ +45,5 @@
> +
> +  /**
> +   * Closes all sessions associated with this Reader and its associated channels.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .

Ah! Actually I have misunderstood your question earlier.
Now I have made changes to close() API (closeAll()) to resolve to boolean true on success.

@@ +49,5 @@
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .
> +   */
> +  // Promise<MozSEReader>
> +  [Throws]
> +  Promise close();

Ok. I have renamed to closeAll().

@@ +61,5 @@
> +
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided

If I understand your question here ( Pls correct me if I have not! )

why use Cached & Pure? If I don't, and I simply use say, 'readonly attribute sequence<octet> atr;' build system throws an error : "WebIDL.WebIDLError: error: A non-cached attribute cannot be of a sequence type" - Implies that we should use 'cached'

If I don't use 'Pure' keyword : build system throws an error saying 'WebIDL.WebIDLError: error: Cached attributes and attributes stored in slots must be constant or pure, since the getter won't always be called.'

Your other question on 'why can't TypedArrays be used here ?'
It looks like the traditional typed arrays (like say Unit8Array, or say even ArrayBuffer) usage in webIDL with a corresponding JS implementation doesn't quite generate the necessary MozXXXBindings correctly and bails out during the build process. Also aren't 'sequences' also some sort of typed arrays, but its kind is not transparent to its users ?

@@ +62,5 @@
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided
> +  [Cached, Pure] readonly attribute sequence<octet> atr;

Hopefully above explanation takes this question too.

@@ +98,5 @@
> +  /**
> +   * Closes the active communication channel to the application on Secure Element. This will also
> +   * close all other active channels associated with this session.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSESession object that is closed.

Got it! Misinterpreted your last comment. Now closeAll() is resolved to boolean true on success

@@ +130,5 @@
> +   * MozSEResponse object. Otherwise, rejected with the error of type 'SEError'.
> +   */
> +  // Promise<MozSEResponse>
> +  [Throws]
> +  Promise transmit(MozSECommand command);

Updated the prose by mentioning it as an 'atomic operation & etc..'

@@ +135,5 @@
> +
> +  /**
> +   * Closes the active channel.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEChannel object that is closed.

Ignore my prev. answer please. Addressed this in the latest iteration.

@@ +147,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SECommand;1",
> + Constructor(octet cla, octet ins, octet p1, octet p2, optional sequence<octet>? data = null, optional short le= -1)]

Ok. Since the Mozxxxbindings will not be generated correctly by the build, should be we use regular typed arrays (with a JS implementation), what do you suggest ? Do you want me to add this bug as a blocker to SecureElement API (This feature is slated for 2.2 REL)  ?

@@ +163,5 @@
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="CertifiedApps",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/secureelement/SEResponse;1",
> + Constructor(octet sw1, octet sw2, sequence<octet> data)]

On second thoughts, we may not need a constructor! and this object will be constructed by gecko (chrome obj) and send it to the gaia apps

::: dom/webidl/MozSecureElementManager.webidl
@@ +3,5 @@
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +[JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager",
> + Func="Navigator::HasSecureElementManagerSupport"]

Something in this order in Navigator.cpp

bool
Navigator::HasSecureElementManagerSupport(JSContext* /* unused */, JSObject* aGlobal)
{
  nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);

  nsCOMPtr<nsIPermissionManager> permMgr =
    services::GetPermissionManager();
  NS_ENSURE_TRUE(permMgr, false);

  uint32_t permission = nsIPermissionManager::DENY_ACTION;
  permMgr->TestPermissionFromPrincipal(principal, "secureelement-manage", &permission);
  return nsIPermissionManager::ALLOW_ACTION == permission;

}

@@ +12,5 @@
> +   *
> +   * @return If success, the promise is resolved to  an array of instances
> +   *        of MozSEReaders Otherwise, rejected with an error.
> +   */
> +  // Promise<MozSEReader[]>

Fixed!
(Assignee)

Comment 86

3 years ago
Created attachment 8466403 [details] [diff] [review]
(v1.7) Secure Element APIs - Inital Draft
Attachment #8465143 - Attachment is obsolete: true
Attachment #8466403 - Flags: feedback?(ehsan)
Comment on attachment 8465143 [details] [diff] [review]
(v1.6) Secure Element APIs - Inital Draft

Review of attachment 8465143 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElement.webidl
@@ +45,5 @@
> +
> +  /**
> +   * Closes all sessions associated with this Reader and its associated channels.
> +   *
> +   * @return If success, the promise is resolved to current instance of MozSEReader object that is closed .

With promises, resolving the promise itself is considered as a sign of the operation completing successfully.  To signal failures, you reject the promise.  So I don't think we need to resolve these to booleans.

@@ +61,5 @@
> +
> +  // Status of current session
> +  readonly attribute boolean isClosed;
> +
> +  // Answer to Reset provided by the secure element, null if not provided

No, sequences do not use typed arrays under the hood.  I think you should look into whether we can fix the WebIDL issue which prevents typed arrays from being used on JS implemnented interfaces, and use them in this API.

::: dom/webidl/MozSecureElementManager.webidl
@@ +3,5 @@
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +[JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager",
> + Func="Navigator::HasSecureElementManagerSupport"]

OK, then a simple [CheckPermission] should suffice.
Comment on attachment 8466403 [details] [diff] [review]
(v1.7) Secure Element APIs - Inital Draft

Review of attachment 8466403 [details] [diff] [review]:
-----------------------------------------------------------------

(See the previous comment please.)
Attachment #8466403 - Flags: feedback?(ehsan) → feedback-
(Assignee)

Comment 89

3 years ago
Hi Ehsan,
Just wanted to update you that I am in receipt of your latest comments. I have addressed (promise not resolving to a boolean) and adding '[CheckPermission]' flag to the interface. I will upload these changes in the next iteration as soon the bigger issue is cleared, since the bigger blocker here is the possibility of using Typed Arrays. I will request for update on the aforementioned bug (that adds TypedArray support to JS impl). I will keep you posted.
Also pls note that I have early functional implementation using the proposed interfaces.

Thanks, Sid
Sounds good, thanks Sid!
(Assignee)

Updated

3 years ago
Depends on: 1054029
Keywords: dev-doc-needed
Depends on: 929609
(Assignee)

Comment 91

3 years ago
Created attachment 8480077 [details] [diff] [review]
(v1.8) Secure Element APIs - Inital Draft

I also tested out this interface files with latest patch Boris Zbarsky [:bz].
Attachment #8466403 - Attachment is obsolete: true
Attachment #8480077 - Flags: review?(ehsan)
Comment on attachment 8480077 [details] [diff] [review]
(v1.8) Secure Element APIs - Inital Draft

Review of attachment 8480077 [details] [diff] [review]:
-----------------------------------------------------------------

Please provide an interdiff.  Thanks.
Attachment #8480077 - Flags: review?(ehsan)
(Assignee)

Comment 93

3 years ago
Hopefully this diff should help.
https://bugzilla.mozilla.org/attachment.cgi?oldid=8466403&action=interdiff&newid=8480077&headers=1

Here are the changes between previous version (1.7) and current one (1.8)
   
1) Use TypedArrays 'Uint8Array' instead of 'sequence<octet>' : One of the review comments 

-  openLogicalChannel
-  openBasicChannel
-  readonly attribute Unit8Array atr

2) 'close()' & 'closeAll()' interfaces do not resolve to a 'boolean' any more. ('void' instead) : One of the review comments

3) 'interface SEManager' has the property 'CheckPermissions="secureelement-manage"' instead of 'Func="Navigator::HasSecureElementManagerSupport"' : One of the review comments

4) Modified all interface definitions to be in consistent with other webidl definitions (across all subsystems) on Mainline.
   
Example: Instead of declaring an interface: 'Promise openSession()', in the latest iteration it gets modified to 'Promise<SESession> openSession()'
The above change is applicable to all the interfaces across MozSecureElement.webidl & MozSecureElementManager.webidl
(Assignee)

Updated

3 years ago
Flags: needinfo?(ehsan.akhgari)
Attachment #8480077 - Flags: review+
Flags: needinfo?(ehsan.akhgari)
I've been writing a sample code using the current version of this API. One thing I noticed is that developers will need to store the reference to the channel and reader in order to close them once not needed anymore.

For instance:

> // Developer will need to store some references. Once possibility is to have them
> // in the outer scope, like shown below.
> var reader, channel;
> 
> var openSession = function(readers) { 
>   // We need to store this (or session/channel) to be able to cleanup later
>   reader = readers[0];
>   return reader.openSession(); 
> };
> 
> var openChannel = function(session) { return session.openLogicalChannel(...); };
> 
> var sendFirstAPDU = function(_channel) {
>   // We need to store this to be able to send multiple APDU's
>   channel = _channel;
>   return channel.transmit(...);
> };
> 
> var sendSecondAPDU = function(response) {
>   // Here we use the previously saved channel reference
>   return channel.transmit(...);
> };
> 
> var cleanup = function(response) {
>   // Here we use the previously saved reader reference
>   return reader.closeAll();
> };
> 
> window.navigator.mozSEManager.getSEReaders()
>   .then(openSession)
>   .then(openChannel)
>   .then(sendFirstAPDU)
>   .then(sendSecondAPDU)
>   .then(cleanup)
>   .catch(...);

Maybe we could make it a bit easier for the developers, by having the reference to reader in the child sessions, to session in the child channels etc. Then, we could modify the above code by removing the references to reader and session, i.e.:

> // ...
> 
> var sendSecondAPDU = function(response) {
>   // Here we use the response to obtain the channel.
>   return response.channel.transmit(...);
> };
> 
> // ...
> var cleanup = function(response) {
>   // Samer here - we don't use the reference from the outer scope
>   return response.channel.session.reader.closeAll();
> };
> 
> // ...

Of course, we could solve this in some other way as well - namely make the API methods resolve promises not to the value itself, but to an object containing value *and some additional references*, i.e.

> var sendSecondAPDU = function(resolved) {
>   console.log('Response is', resolved.value);
>   return resolved.channel.transmit(...);
> };

Effectively, this approach is a bit more confusing IMO.

What do you think, should we consider making this kind of changes to the API in order to make it a bit easier to write clean code on the Gaia/3rd party side?
Flags: needinfo?(ehsan.akhgari)
Flags: needinfo?(allstars.chh)
That is a great point.  I think we can improve things by the following changes, written as partial interfaces:

partial interface SEChannel {
  readonly attribute SEReader reader;
};

partial interface SEResponse {
  readonly attribute SEChannel channel;
};

Would that address your concerns?
Flags: needinfo?(ehsan.akhgari) → needinfo?(kamituel)
Comment on attachment 8480077 [details] [diff] [review]
(v1.8) Secure Element APIs - Inital Draft

Review of attachment 8480077 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/MozSecureElementManager.webidl
@@ +4,5 @@
> +
> +[CheckPermissions="secureelement-manage",
> + AvailableIn="PrivilegedApps",
> + JSImplementation="@mozilla.org/navigatorSEManager;1",
> + NavigatorProperty="mozSEManager"]

For some reason I didn't catch this before...  Please rename this to seManager or some such.

Also, there is no reason to have the Moz prefix on the WebIDL files either.
Attachment #8480077 - Flags: review+ → review-
Yes, adding those two references is enough to cover mentioned use case. Thanks! (I just talked to Sid and he'll add them to the IDL in the next iteration).
Flags: needinfo?(kamituel)
Great!
(Assignee)

Comment 99

3 years ago
Created attachment 8486041 [details] [diff] [review]
(v1.9) Secure Element APIs - Inital Draft

Changes :
- Renamed navigator property from 'MozSEManager' to 'seManager'.
- Renamed files : Removed 'moz' prefix.
- Added two partial interfaces. (Thanks Kamil for bringing up the concern and Thanks Ehsan for suggesting the improvement)
Attachment #8480077 - Attachment is obsolete: true
Attachment #8486041 - Flags: review?(ehsan.akhgari)
(Assignee)

Comment 100

3 years ago
Created attachment 8486156 [details] [diff] [review]
(v1.9) Secure Element APIs - Inital Draft
Attachment #8486041 - Attachment is obsolete: true
Attachment #8486041 - Flags: review?(ehsan.akhgari)
Attachment #8486156 - Flags: review?(ehsan.akhgari)
(In reply to Kamil Leszczuk [:kamituel] from comment #94)
> > var sendFirstAPDU = function(_channel) {
> >   // We need to store this to be able to send multiple APDU's
> >   channel = _channel;
> >   return channel.transmit(...);
> > };
> > 
> > var sendSecondAPDU = function(response) {
> >   // Here we use the previously saved channel reference
> >   return channel.transmit(...);
> > };
> > 

You should pass 'channel' not 'response'.

(In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!) from comment #95)
> partial interface SEChannel {
>   readonly attribute SEReader reader;
> };
> 
The attribute should be 'session'.
And session should have an attribute 'reader'.
And OpenMobileAPI has already defined these getters.


> partial interface SEResponse {
>   readonly attribute SEChannel channel;
> };
> 
The SEResponse/SECommand should implement ISO 7816-4, however they doesn't have any context of 'Channel'.
Also with what I've replied to Kamil, do we still need to add this attribute?


And why these attributes are defined in 'partial' interface?
Flags: needinfo?(allstars.chh)
Comment on attachment 8486156 [details] [diff] [review]
(v1.9) Secure Element APIs - Inital Draft

Review of attachment 8486156 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/webidl/SecureElement.webidl
@@ +2,5 @@
> + * License, v. 2.0. If a copy of the MPL was not distributed with this
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +enum SEType {
> +  "uicc",

From Bug 979767, it's called 'SIM'.
Please make the naming consistent
(Assignee)

Updated

3 years ago
Attachment #8486156 - Flags: review?(ehsan.akhgari)
(In reply to Yoshi Huang[:allstars.chh] from comment #101)

> You should pass 'channel' not 'response'.

Hm, I think response will be passed to that method, not a channel. Consider this more complete example: https://gist.github.com/kamituel/264ee1683c5a3f805be0 - note that this is a handler for a second APDU being transmitted, not the first.
Flags: needinfo?(allstars.chh)
Some more notes regarding API usage:

1) Currently, once we call session.openLogicalChannel(), we will get a promise which will get resolved to the SEChannel instance. In case of SIM based secure element, this command will map to the RIL SELECT command being send to the SIM card. Response to this command will contain some data in addition to the (hopefully) 9000 status code. 

As it turns out, data from the response could be application specific, so the Gaia app should have a way of retrieving it once the channel is opened. In the Open Mobile API, there is a |byte[] Channel.getSelectResponse()| method specifically used for that. We should probably have something similar as well.


2) There are some non-9000 success responses - i.e. some responses mean that there client should issue more command to fetch rest of the data. How would we handle them? 

Couple of ideas:

a) we could not handle them. I.e. if response is 9Fxx, we would pass it to the Gaia app as it is, and let developer handle it.
 - Pros: simple implementation on our side. 
 - Cons: developer has to worry about some really low level stuff, like concatenating single piece of data coming in multiple messages. 

b) we could handle those in a SE DOM implementation and pass the already concatenated data to the Gaia app. 
 - Pros: easy for the developer 
 - Cons: harder on us ;)

c) we could not handle them in the SE DOM impl, pass as they are to the Gaia app, but also provide developers with the shared/se_utils.js library which would help with that.
 - Pros: stil quite simple for the developer. We're not making the SE DOM impl complex
 - Cons: it'd be good if we would develop that library.

Of course, there could be some other success responses than the ones requiring fetching more data. The above points would apply to them as well, probably.

What do you think?
Flags: needinfo?(ehsan.akhgari)
(In reply to Kamil Leszczuk [:kamituel] from comment #104)
> Some more notes regarding API usage:
> 
> 1) Currently, once we call session.openLogicalChannel(), we will get a
> promise which will get resolved to the SEChannel instance. In case of SIM
> based secure element, this command will map to the RIL SELECT command being
> send to the SIM card. Response to this command will contain some data in
> addition to the (hopefully) 9000 status code. 
> 
> As it turns out, data from the response could be application specific, so
> the Gaia app should have a way of retrieving it once the channel is opened.
> In the Open Mobile API, there is a |byte[] Channel.getSelectResponse()|
> method specifically used for that. We should probably have something similar
> as well.

OK, sounds good.  If I understand things correctly, this data is sent back as part of the response, so it should be available as soon as we resolve the promise.  If that is correct, then we can expose this as a nullable readonly typed array property on SEChannel (it would be null for other types of channels.)

> 2) There are some non-9000 success responses - i.e. some responses mean that
> there client should issue more command to fetch rest of the data. How would
> we handle them? 
> 
> Couple of ideas:
> 
> a) we could not handle them. I.e. if response is 9Fxx, we would pass it to
> the Gaia app as it is, and let developer handle it.
>  - Pros: simple implementation on our side. 
>  - Cons: developer has to worry about some really low level stuff, like
> concatenating single piece of data coming in multiple messages. 
> 
> b) we could handle those in a SE DOM implementation and pass the already
> concatenated data to the Gaia app. 
>  - Pros: easy for the developer 
>  - Cons: harder on us ;)
> 
> c) we could not handle them in the SE DOM impl, pass as they are to the Gaia
> app, but also provide developers with the shared/se_utils.js library which
> would help with that.
>  - Pros: stil quite simple for the developer. We're not making the SE DOM
> impl complex
>  - Cons: it'd be good if we would develop that library.
> 
> Of course, there could be some other success responses than the ones
> requiring fetching more data. The above points would apply to them as well,
> probably.
> 
> What do you think?

How hard would it be to deal with these extra status codes inside the DOM implementation?  I think if it's not prohibitively complicated, I would prefer to deal with these types of details in the implementation of the API, and try to remove as much of the burden from the consumer of the API as possible.
Flags: needinfo?(ehsan.akhgari)
(Assignee)

Comment 106

3 years ago
(In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!) from comment #105)
> (In reply to Kamil Leszczuk [:kamituel] from comment #104)
> > Some more notes regarding API usage:
> > 
> > 1) Currently, once we call session.openLogicalChannel(), we will get a
> > promise which will get resolved to the SEChannel instance. In case of SIM
> > based secure element, this command will map to the RIL SELECT command being
> > send to the SIM card. Response to this command will contain some data in
> > addition to the (hopefully) 9000 status code. 
> > 
> > As it turns out, data from the response could be application specific, so
> > the Gaia app should have a way of retrieving it once the channel is opened.
> > In the Open Mobile API, there is a |byte[] Channel.getSelectResponse()|
> > method specifically used for that. We should probably have something similar
> > as well.
> 
> OK, sounds good.  If I understand things correctly, this data is sent back
> as part of the response, so it should be available as soon as we resolve the
> promise.  If that is correct, then we can expose this as a nullable readonly
> typed array property on SEChannel (it would be null for other types of
> channels.)
> 

Quick note. 'openLogicalChannel' will be mapped to 'AT+CCHO' on the vendor RIL side. This is in turn broken down into two APDU commands that are executed on the baseband side.
APDU COMMAND 1: MANAGE OPEN CHANNEL
APDU COMMAND 2: SELECT COMMAND (0x00, 0xA4, 0x04, 0x00) + passed in 'aid' of the applet in +CCHO command.

As a consequence of first command, a 'session ID' ('Session' object encapsulates it) is returned, while second command yields the result of optional 'getSelectResponse()' (or) "nullable readonly
typed array property". Please note that this is an optional response by the baseband. (Mostly 'null' for Logical channels. Earlier experiments on Nexus-S device gave us 'null' for logical channels. However note that for the basic channel, the response could be a non-null value. (Basic channel access may not be honored on Qualcomm basebands for security reasons). In the current iteration, since we are dealing with UICC SE (and logical channels) mostly, we have not considered adding the 'response' attribute). If we plan to support this attribute we should also request Qualcomm to see if they indeed support such on the flame reference and release device. 
Also if the point is for the sake of completion of the API, we should go ahead and add it.

> > 2) There are some non-9000 success responses - i.e. some responses mean that
> > there client should issue more command to fetch rest of the data. How would
> > we handle them? 
> > 
> > Couple of ideas:
> > 
> > a) we could not handle them. I.e. if response is 9Fxx, we would pass it to
> > the Gaia app as it is, and let developer handle it.
> >  - Pros: simple implementation on our side. 
> >  - Cons: developer has to worry about some really low level stuff, like
> > concatenating single piece of data coming in multiple messages. 
> > 
> > b) we could handle those in a SE DOM implementation and pass the already
> > concatenated data to the Gaia app. 
> >  - Pros: easy for the developer 
> >  - Cons: harder on us ;)
> > 
> > c) we could not handle them in the SE DOM impl, pass as they are to the Gaia
> > app, but also provide developers with the shared/se_utils.js library which
> > would help with that.
> >  - Pros: stil quite simple for the developer. We're not making the SE DOM
> > impl complex
> >  - Cons: it'd be good if we would develop that library.
> > 
> > Of course, there could be some other success responses than the ones
> > requiring fetching more data. The above points would apply to them as well,
> > probably.
> > 
> > What do you think?
> 
> How hard would it be to deal with these extra status codes inside the DOM
> implementation?  I think if it's not prohibitively complicated, I would
> prefer to deal with these types of details in the implementation of the API,
> and try to remove as much of the burden from the consumer of the API as
> possible.

In the current prototype impl. responses such as 9x00 and 6x00 (generally errors) are all handled in DOM implementation and returned transparently in SW1 & SW2 values of SEResponse interface. Since these code are pretty much standard error codes, we have not added any extra helper functions. Sure we could add extra helper function like getStatus() or 'readonly attribute status' or some such to ease the burden of the API users
(In reply to Siddartha P from comment #106)
> (In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!) from
> comment #105)
> > (In reply to Kamil Leszczuk [:kamituel] from comment #104)
> > > Some more notes regarding API usage:
> > > 
> > > 1) Currently, once we call session.openLogicalChannel(), we will get a
> > > promise which will get resolved to the SEChannel instance. In case of SIM
> > > based secure element, this command will map to the RIL SELECT command being
> > > send to the SIM card. Response to this command will contain some data in
> > > addition to the (hopefully) 9000 status code. 
> > > 
> > > As it turns out, data from the response could be application specific, so
> > > the Gaia app should have a way of retrieving it once the channel is opened.
> > > In the Open Mobile API, there is a |byte[] Channel.getSelectResponse()|
> > > method specifically used for that. We should probably have something similar
> > > as well.
> > 
> > OK, sounds good.  If I understand things correctly, this data is sent back
> > as part of the response, so it should be available as soon as we resolve the
> > promise.  If that is correct, then we can expose this as a nullable readonly
> > typed array property on SEChannel (it would be null for other types of
> > channels.)
> > 
> 
> Quick note. 'openLogicalChannel' will be mapped to 'AT+CCHO' on the vendor
> RIL side. This is in turn broken down into two APDU commands that are
> executed on the baseband side.
> APDU COMMAND 1: MANAGE OPEN CHANNEL
> APDU COMMAND 2: SELECT COMMAND (0x00, 0xA4, 0x04, 0x00) + passed in 'aid' of
> the applet in +CCHO command.
> 
> As a consequence of first command, a 'session ID' ('Session' object
> encapsulates it) is returned, while second command yields the result of
> optional 'getSelectResponse()' (or) "nullable readonly
> typed array property". Please note that this is an optional response by the
> baseband. (Mostly 'null' for Logical channels. Earlier experiments on
> Nexus-S device gave us 'null' for logical channels. However note that for
> the basic channel, the response could be a non-null value. (Basic channel
> access may not be honored on Qualcomm basebands for security reasons). In
> the current iteration, since we are dealing with UICC SE (and logical
> channels) mostly, we have not considered adding the 'response' attribute).
> If we plan to support this attribute we should also request Qualcomm to see
> if they indeed support such on the flame reference and release device. 
> Also if the point is for the sake of completion of the API, we should go
> ahead and add it.

Hmm, so assuming I understand the above correctly, does this mean that the response property may not work on some chipsets/drivers?

> > > 2) There are some non-9000 success responses - i.e. some responses mean that
> > > there client should issue more command to fetch rest of the data. How would
> > > we handle them? 
> > > 
> > > Couple of ideas:
> > > 
> > > a) we could not handle them. I.e. if response is 9Fxx, we would pass it to
> > > the Gaia app as it is, and let developer handle it.
> > >  - Pros: simple implementation on our side. 
> > >  - Cons: developer has to worry about some really low level stuff, like
> > > concatenating single piece of data coming in multiple messages. 
> > > 
> > > b) we could handle those in a SE DOM implementation and pass the already
> > > concatenated data to the Gaia app. 
> > >  - Pros: easy for the developer 
> > >  - Cons: harder on us ;)
> > > 
> > > c) we could not handle them in the SE DOM impl, pass as they are to the Gaia
> > > app, but also provide developers with the shared/se_utils.js library which
> > > would help with that.
> > >  - Pros: stil quite simple for the developer. We're not making the SE DOM
> > > impl complex
> > >  - Cons: it'd be good if we would develop that library.
> > > 
> > > Of course, there could be some other success responses than the ones
> > > requiring fetching more data. The above points would apply to them as well,
> > > probably.
> > > 
> > > What do you think?
> > 
> > How hard would it be to deal with these extra status codes inside the DOM
> > implementation?  I think if it's not prohibitively complicated, I would
> > prefer to deal with these types of details in the implementation of the API,
> > and try to remove as much of the burden from the consumer of the API as
> > possible.
> 
> In the current prototype impl. responses such as 9x00 and 6x00 (generally
> errors) are all handled in DOM implementation and returned transparently in
> SW1 & SW2 values of SEResponse interface. Since these code are pretty much
> standard error codes, we have not added any extra helper functions. Sure we
> could add extra helper function like getStatus() or 'readonly attribute
> status' or some such to ease the burden of the API users

My suggestion is to not put that burden on the consumer of the API.
(In reply to Kamil Leszczuk [:kamituel] from comment #103)
> (In reply to Yoshi Huang[:allstars.chh] from comment #101)
> 
> > You should pass 'channel' not 'response'.
> 
> Hm, I think response will be passed to that method, not a channel. Consider
> this more complete example:
> https://gist.github.com/kamituel/264ee1683c5a3f805be0 - note that this is a
> handler for a second APDU being transmitted, not the first.

It seems to me sendFirstAPDU should return a promise resolved to 'channel' since 'response' isn't used in your sendSecondAPDU.

var sendFirstAPDU = function(channel) {
  var apdu = new SECommand('A', 'B', 'C', 'D');
  return channel.transmit(apdu);
};

Also I think this should be handled in the application layer, originally the intention of this bug is to implement the SE API which comforms to OpenMobile API, adding an attribute which isn't included in the original OpenMobileAPI needs more discussions and I'd prefer file another bug for this.
Flags: needinfo?(allstars.chh)
No longer blocks: 979158
Whiteboard: [ETA: 12/15]
No longer depends on: 921320
(Assignee)

Comment 109

3 years ago
(In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!, PTO on Thu/Fri) from comment #107)
> (In reply to Siddartha P from comment #106)
> > (In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!) from
> > comment #105)
> > > (In reply to Kamil Leszczuk [:kamituel] from comment #104)
> > > > Some more notes regarding API usage:
> > > > 
> > > > 1) Currently, once we call session.openLogicalChannel(), we will get a
> > > > promise which will get resolved to the SEChannel instance. In case of SIM
> > > > based secure element, this command will map to the RIL SELECT command being
> > > > send to the SIM card. Response to this command will contain some data in
> > > > addition to the (hopefully) 9000 status code. 
> > > > 
> > > > As it turns out, data from the response could be application specific, so
> > > > the Gaia app should have a way of retrieving it once the channel is opened.
> > > > In the Open Mobile API, there is a |byte[] Channel.getSelectResponse()|
> > > > method specifically used for that. We should probably have something similar
> > > > as well.
> > > 
> > > OK, sounds good.  If I understand things correctly, this data is sent back
> > > as part of the response, so it should be available as soon as we resolve the
> > > promise.  If that is correct, then we can expose this as a nullable readonly
> > > typed array property on SEChannel (it would be null for other types of
> > > channels.)
> > > 
> > 
> > Quick note. 'openLogicalChannel' will be mapped to 'AT+CCHO' on the vendor
> > RIL side. This is in turn broken down into two APDU commands that are
> > executed on the baseband side.
> > APDU COMMAND 1: MANAGE OPEN CHANNEL
> > APDU COMMAND 2: SELECT COMMAND (0x00, 0xA4, 0x04, 0x00) + passed in 'aid' of
> > the applet in +CCHO command.
> > 
> > As a consequence of first command, a 'session ID' ('Session' object
> > encapsulates it) is returned, while second command yields the result of
> > optional 'getSelectResponse()' (or) "nullable readonly
> > typed array property". Please note that this is an optional response by the
> > baseband. (Mostly 'null' for Logical channels. Earlier experiments on
> > Nexus-S device gave us 'null' for logical channels. However note that for
> > the basic channel, the response could be a non-null value. (Basic channel
> > access may not be honored on Qualcomm basebands for security reasons). In
> > the current iteration, since we are dealing with UICC SE (and logical
> > channels) mostly, we have not considered adding the 'response' attribute).
> > If we plan to support this attribute we should also request Qualcomm to see
> > if they indeed support such on the flame reference and release device. 
> > Also if the point is for the sake of completion of the API, we should go
> > ahead and add it.
> 
> Hmm, so assuming I understand the above correctly, does this mean that the
> response property may not work on some chipsets/drivers?
> 
I owe you a reply on this one. Yes it may be an optional response on some chipsets

> > > > 2) There are some non-9000 success responses - i.e. some responses mean that
> > > > there client should issue more command to fetch rest of the data. How would
> > > > we handle them? 
> > > > 
> > > > Couple of ideas:
> > > > 
> > > > a) we could not handle them. I.e. if response is 9Fxx, we would pass it to
> > > > the Gaia app as it is, and let developer handle it.
> > > >  - Pros: simple implementation on our side. 
> > > >  - Cons: developer has to worry about some really low level stuff, like
> > > > concatenating single piece of data coming in multiple messages. 
> > > > 
> > > > b) we could handle those in a SE DOM implementation and pass the already
> > > > concatenated data to the Gaia app. 
> > > >  - Pros: easy for the developer 
> > > >  - Cons: harder on us ;)
> > > > 
> > > > c) we could not handle them in the SE DOM impl, pass as they are to the Gaia
> > > > app, but also provide developers with the shared/se_utils.js library which
> > > > would help with that.
> > > >  - Pros: stil quite simple for the developer. We're not making the SE DOM
> > > > impl complex
> > > >  - Cons: it'd be good if we would develop that library.
> > > > 
> > > > Of course, there could be some other success responses than the ones
> > > > requiring fetching more data. The above points would apply to them as well,
> > > > probably.
> > > > 
> > > > What do you think?
> > > 
> > > How hard would it be to deal with these extra status codes inside the DOM
> > > implementation?  I think if it's not prohibitively complicated, I would
> > > prefer to deal with these types of details in the implementation of the API,
> > > and try to remove as much of the burden from the consumer of the API as
> > > possible.
> > 
> > In the current prototype impl. responses such as 9x00 and 6x00 (generally
> > errors) are all handled in DOM implementation and returned transparently in
> > SW1 & SW2 values of SEResponse interface. Since these code are pretty much
> > standard error codes, we have not added any extra helper functions. Sure we
> > could add extra helper function like getStatus() or 'readonly attribute
> > status' or some such to ease the burden of the API users
> 
> My suggestion is to not put that burden on the consumer of the API.
Ok. I looked at the specs and here are some status words (sw1 & sw2 respectively)
90 00 - Success
62 00 - Logical Channel Already Closed
68 82 - Secure Messaging Not supported
6A 81 - Function not supported eg:- Cycle state is CARD_LOCKED
62 83 - Card Life  Cycle State is CARD_LOCKED
6A 82 - Selected Application / file not found
6A 80 - Incorrect Values in command data 
6A 88 - Reference data not found
64 00 - No Specific diagnosis
67 00 - Wrong Length in Lc
68 81 - Logical channel not supported or is not active
69 82 - Security Status not satisfied
69 85 - Conditions of use not satisfied
6A 86 - Incorrect p1 p2
6D 00 - Invalid instruction
6E 00 - Invalid Class
65 81 - Memory Failure
6A 88 - Reference data not found
6A 82 - Application not found
6A 82 - Not enough memory space
63 10 - More data available
Note that there are many more sw1 & sw2 combinations possible. For example , a whole series of 91 xx & 94 XX are not listed yet. (List could be exhaustive).
(Assignee)

Comment 110

3 years ago
Created attachment 8491514 [details] [diff] [review]
(v1.9) Secure Element APIs - Inital Draft

Changes :
- Renamed navigator property from 'MozSEManager' to 'seManager'.
- Renamed files : Removed 'moz' prefix.
- Added the parent object as 'readonly attribute' to Child interfaces.
- Renamed the enum "uicc" to "SIM" to be inconsistent with the spec.
Attachment #8486156 - Attachment is obsolete: true
Attachment #8491514 - Flags: review?(ehsan.akhgari)

Comment 111

3 years ago
My suggestions:

- yes, the parent reference is good to add

- "UICC" is better than "SIM". UICC is the mobile's smart card (ie secure element), which is what you identify here. SIM is only one of the possible applications in that card, and furthermore a legacy one. See http://en.wikipedia.org/wiki/Universal_Integrated_Circuit_Card for more details.

- the Channel interface should have an "openResponse" readonly field to get the response from the select command which was used during the openChannel operation. This is in the W3C proposal http://opoto.github.io/secure-element/

- it might be useful to also add the selectNext() method to support openChannel operations on partial AIDs. This allows to select a set of SE applications and iterate over them. This is also in the W3C proposal. 

- this Channel object should not interpret the response from the secure element, as there are may be many cases that may require incompatible behaviors. It will be easy to provide (in the platform, or by 3rd parties) helpers in the form of Promise objects, that will handle each of these particular cases. The application would use something like:

  var apdu = new SECommand('1', '2', '3', '4');
  channel.transmit(apdu).then(aSpecificResponseHelper)
                        .then(doMyBusiness)
(Assignee)

Updated

3 years ago
Attachment #8491514 - Flags: review?(ehsan.akhgari)
(Assignee)

Comment 112

3 years ago
(In reply to opoto from comment #111)
> My suggestions:
> 
> - yes, the parent reference is good to add
> 
Ok.
> - "UICC" is better than "SIM". UICC is the mobile's smart card (ie secure
> element), which is what you identify here. SIM is only one of the possible
> applications in that card, and furthermore a legacy one. See
> http://en.wikipedia.org/wiki/Universal_Integrated_Circuit_Card for more
> details.
> 
Ok. I will update the IDL with "uicc" again. As per the bug landed by Garner, From Bug 979767, it's referred to as 'SIM'. I will request Garner to raise another bug and change it to 'uicc' to keep it consistent.
> - the Channel interface should have an "openResponse" readonly field to get
> the response from the select command which was used during the openChannel
> operation. This is in the W3C proposal http://opoto.github.io/secure-element/
> 
Ok. I will add this one. But as I said, this will be an optional implementation on Qualcomm basebands.
Mostly it may be null.
> - it might be useful to also add the selectNext() method to support
> openChannel operations on partial AIDs. This allows to select a set of SE
> applications and iterate over them. This is also in the W3C proposal. 
> 
Since , in the first iteration of SE implementation, 'partial AIDs' may not be fully supported by the stack. Maybe this interface will be appropriate to add once we have 'partial AID' support. 
> - this Channel object should not interpret the response from the secure
> element, as there are may be many cases that may require incompatible
> behaviors. It will be easy to provide (in the platform, or by 3rd parties)
> helpers in the form of Promise objects, that will handle each of these
> particular cases. The application would use something like:
> 
>   var apdu = new SECommand('1', '2', '3', '4');
>   channel.transmit(apdu).then(aSpecificResponseHelper)
>                         .then(doMyBusiness)
Yes, agreed.
Depends on: 1081789

Updated

3 years ago
Duplicate of this bug: 1030602

Comment 114

3 years ago
http://lists.w3.org/Archives/Public/public-web-security/2014Oct/0022.html

So you are on the right track guys, it is rather the W3C who needs to rethink their value proposition.

Regards,
Anders Rundgren
feature-b2g: --- → 2.2+

Updated

3 years ago
Depends on: 1016003
Comment on attachment 8491514 [details] [diff] [review]
(v1.9) Secure Element APIs - Inital Draft

I have some questions when reviewing the test case for SE API.

>+  [Throws]
>+  Promise<SEChannel> openLogicalChannel(Uint8Array  aid);
>+
nit, an extra ws before 'aid', same for below in openBasicChannel.

>+  /**
>+   * Closes the active communication channel to the application on Secure Element. This will also
>+   * close all other active channels associated with this session.
>+   *
Can these two lines be merged into
"Close all active channels associated with this session." ?
or what's the difference between the first and the second sentences?

Also does this method close the session itself?
>+   */
>+  [Throws]
>+  Promise<void> closeAll();
>+};
>+
(Assignee)

Comment 116

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #115)
> Comment on attachment 8491514 [details] [diff] [review]
> (v1.9) Secure Element APIs - Inital Draft
> 
> I have some questions when reviewing the test case for SE API.
> 
> >+  [Throws]
> >+  Promise<SEChannel> openLogicalChannel(Uint8Array  aid);
> >+
> nit, an extra ws before 'aid', same for below in openBasicChannel.
> 
ok . I will fix this in the next iteration.
> >+  /**
> >+   * Closes the active communication channel to the application on Secure Element. This will also
> >+   * close all other active channels associated with this session.
> >+   *
> Can these two lines be merged into
> "Close all active channels associated with this session." ?
> or what's the difference between the first and the second sentences?
> 

I think we can merge the two lines as you said

> Also does this method close the session itself?
> >+   */
> >+  [Throws]
> >+  Promise<void> closeAll();
> >+};
> >+
Yes the session will become invalid after this statement.
(In reply to Siddartha P from comment #116)
> > Also does this method close the session itself?
> > >+   */
> > >+  [Throws]
> > >+  Promise<void> closeAll();
> > >+};
> > >+
> Yes the session will become invalid after this statement.

Then please update the comment as well, comments doesn't mention this session will be closed.
There will be one test case from QA side to verify this.
Hi Sid,
When are you planning to upload patch?
Yoshi will be the one to do first review.
Flags: needinfo?(psiddh)
Target Milestone: --- → 2.2 S2 (19dec)
(Assignee)

Comment 119

3 years ago
Hi Wesley,

I am in final stages of preparing the patches. By end of this week (12/ 05 or 12 / 06) , I'd be able to get the patches out for initial feedback / review.
In total we have 5 patches
- WebIDL (Another iteration on top of draft proposal so far reviewed by Ehsan)
- DOM Implementation DOMSecureElement.js
- Parent Process Implementation SecureElement.js
- Build files to enable SecureElement in FxOS
- RIL Patch to be reviewed . (This is already uplpoaded @ https://bugzilla.mozilla.org/show_bug.cgi?id=1081789 for HsinYi review)
- ACE patch (Kamil should be able to share more details about it).
(Assignee)

Updated

3 years ago
Flags: needinfo?(psiddh)
(Assignee)

Comment 120

3 years ago
Created attachment 8533051 [details] [diff] [review]
Patch 1 : (v1.10) Secure Element APIs - Inital Draft

Based on the various comments posted so far on SE webidl proposal, the latest patch tries to incorporate all the suggestions in v1.10 patch.
1) 'uicc' vs'sim', Naming convetion ?
Discussion so far:
  Based on comment# 111 from Olivier it is better to name SE type as 'uicc'
  Also as per Yoshi's comment#102, Bug 979767 uses the naming convention of 'SIM' leading to inconsistency.
Current changes:
  Retained the naming convention as 'uicc' and request Garner to make changes accordingly as a follow-up to Bug 979767. 
  Yoshi, I hope you are ok with this.

2) Holding a reference of parent obj in SESession , SEChannel & SEResponse
Discussion so far:
   This point was raised by Kamil earlier and there was follow-up discussion on this with Ehsan. Yoshi also pointed out to 'OpenMobileAPI' implementation in this regard.
   Also as per comment#101, why do they have to 'Partial interfaces' ?
Current changes:
   In the current patch, no partial interfaces are used. Instead the parent reference is a readonly attribute in interfaces directly.
   Ehsan, I hope you are ok with it. Per comment#95 , it seems that you are inclined to have them defined in 'partial interfaces'. Please review the changes and let us know your thoughts

3) Added openResponse attribute to SEChannel:
Discussion so far:
  OpenResponse is required by Gaia Wallet developers to retreive some useful info , as Krzysztof suggested. I also wondered if this supported by the baseband.
Current changes:
  Based on the Qualcomm image that we received, upon few trials and testing it is found that 'openResponse' is indeed supported by the baseband. We have been testing this interface for the last
  month and a half and it seems to give the desired results.

4) In SECommand, 'data' attribute should be Nullable. 
   As per the spec, this attribute may or may not be set (null). Therefore added '?'

5) openLogicalChannel() argument should be 'Nullable' as per spec. Again added '?'

6) Other minor changes such as adding copyright text, addressing the 'comments' of closeAll() API in SESession.

I hope I have taken into consideration all the comments / concerns. If I have missed out on something, please do raise the flag.

As a follow-up to this patch, I will shortly attach othe supporting patches as well.

Thanks, Sid
Attachment #8491514 - Attachment is obsolete: true
Attachment #8533051 - Flags: review?(ehsan.akhgari)
(Assignee)

Updated

3 years ago
Attachment #8533051 - Attachment description: (v1.10) Secure Element APIs - Inital Draft → Patch 1 : (v1.10) Secure Element APIs - Inital Draft
(Assignee)

Comment 121

3 years ago
Created attachment 8533057 [details] [diff] [review]
Patch 2: (v2.1) Secure Element DOM Implementation

Based on comment#118, adding Yoshi as the first reviewer.
Attachment #8533057 - Flags: review?(allstars.chh)
(Assignee)

Comment 122

3 years ago
Created attachment 8533065 [details] [diff] [review]
Patch 3: (v3.1) Secure Element Parent process Implementation. r=yoshi
Attachment #8533065 - Flags: review?(allstars.chh)
(Assignee)

Comment 123

3 years ago
Created attachment 8533068 [details] [diff] [review]
Patch 4: (v4.1) Add new permission to table - 'secureelement-manage'
Attachment #8533068 - Flags: review?(allstars.chh)
(Assignee)

Comment 124

3 years ago
Created attachment 8533084 [details] [diff] [review]
Patch 5: (v5.1) Add build support for SE feature

This patch (configure.in) needs to be further worked upon before I can request for review.
(Assignee)

Comment 125

3 years ago
I have now uploaded all the five SE patches for feedback / review.
Please note that for the patches to be functional, following changes are needed!
  - https://bugzilla.mozilla.org/show_bug.cgi?id=1081789. [Uploaded the latest RIL patch for HsinYi review ]
  - Also note that , as mentioned earlier, Bug#1081789, is dependent on the changes
https://bugzilla.mozilla.org/show_bug.cgi?id=1030602. (Note that this particular changes is already landed on the main line / master. This change needs to cherry-picked / ported to REL 2.1 branch) .

Current Status of the patches and limitations:
- There are few known limitations with the existing implementation. Maybe we should raise follow-up Bugzilla issues to track these after the initial landing!
a) Multi SIM support in CardEmulation scenarios.
b) Multi SIM Support in simply secure storage scenarios
c) Resource leaks in the form of unclosed channel handles when gecko restarts / crashes during SE transaction.
d) Error propagation with reason code to Gaia Wallet Apps is not completely supported. Very limited support exists for now. These errors should be validated against Alison's test case document.
e) UICC Client ID needs to managed appropriately. For now, it defaults to '0' and is configurable.
f) Extended APDU commands
g) There are few other known issues , I'd raise as soon as I recollect more.

Current Testing Status:
The stack / patches are tested against two Gaia apps that Krzysztof is putting together
i) SIM Access Testing Dev App
ii) Wallet 2.0
They exercise fairly advanced use-cases using a specially provisioned T-Mobile Poland SIM card.
(Assignee)

Comment 126

3 years ago
I forgot to mention another limitation of the patches. These patches are not yet integrated with the ACE module. However we think, it should be a fairly straight forward / simple integration between SE Parent process & ACE.
Comment on attachment 8533057 [details] [diff] [review]
Patch 2: (v2.1) Secure Element DOM Implementation

Review of attachment 8533057 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/secureelement/DOMSecureElement.js
@@ +26,5 @@
> +                                   "nsISyncMessageSender");
> +
> +XPCOMUtils.defineLazyServiceGetter(this, "iccProvider",
> +                   "@mozilla.org/ril/content-helper;1",
> +                   "nsIIccProvider");

Who uses this?

@@ +38,5 @@
> +/*
> + * Helper object that maintains sessionObj and its corresponding
> + * channelObj for a given SE type
> + */
> +let SEStateHelper = {

this helper deserves another part of patch.

@@ +190,5 @@
> +/**
> + * ==============================================
> + * SECommand
> + * ==============================================
> + */

I don't see any documentation in this comment.
Same for below.

@@ +193,5 @@
> + * ==============================================
> + */
> +function SECommand() {}
> +SECommand.prototype = {
> +  __init: function(cla, ins, p1, p2, data, le) {

function name

@@ +199,5 @@
> +    this.ins = ins;
> +    this.p1 = p1;
> +    this.p2 = p2;
> +    this.data = data;
> +    this.le = le;

These members should also be defined in prototype.

@@ +215,5 @@
> + */
> +
> +function SEResponse(aResponseInfo) {
> +  this.sw1 = 0x00;
> +  this.sw2 = 0x00;

these two lines are useless.

@@ +218,5 @@
> +  this.sw1 = 0x00;
> +  this.sw2 = 0x00;
> +  this.data = null;
> +
> +  this.channel = SEStateHelper.getChannelObjByToken(aResponseInfo.token);

data, and channel should be defined in prototype.

@@ +224,5 @@
> +  if (!apduResponse.simResponse || apduResponse.simResponse.length === 0) {
> +    if (DEBUG) debug('APDU Response: Empty / Not Set!');
> +  } else {
> +    this.data = apduResponse.simResponse.slice(0, apduResponse.length);
> +  }

Why so complicated?
aResponseInfo.response.simResponse?

@@ +248,5 @@
> +  this._aid = aChannelInfo.aid;
> +  this._channelToken = aChannelInfo.token;
> +  this._sessionId = aChannelInfo.sessionId;
> +  this.session = null;
> +  this.openResponse = null;

define in prototype.

@@ +260,5 @@
> +  classID: Components.ID("{181ebcf4-5164-4e28-99f2-877ec6fa83b9}"),
> +  contractID: "@mozilla.org/secureelement/SEChannel;1",
> +  QueryInterface: XPCOMUtils.generateQI([]),
> +
> +  initialize: function ic_initialize(win, openResponse) {

what's the ic_ in function name?
And what is the difference between initialize and cstor?

@@ +267,5 @@
> +    // Update 'session' obj
> +    this.session = SEStateHelper.getSessionObjById(this._sessionId);
> +  },
> +
> +  transmit: function(command) {

function name

@@ +275,5 @@
> +    if (typeof command.cla === 'undefined' ||
> +        typeof command.ins === 'undefined' ||
> +        typeof command.p1 === 'undefined' ||
> +        typeof command.p2 === 'undefined' ||
> +        !command)

I think the command is type of SECommand, right?
Why can't these checks be done in SECommand cstor?

@@ +276,5 @@
> +        typeof command.ins === 'undefined' ||
> +        typeof command.p1 === 'undefined' ||
> +        typeof command.p2 === 'undefined' ||
> +        !command)
> +      return PromiseHelpers._rejectWithSEError('SEGenericError: ' +

nit, add {}.

{

  return Promise...
};

@@ +280,5 @@
> +      return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> +                          "Invalid APDU, Missing Mandatory headers!");
> +
> +    let le = -1;
> +    let dataLen = -1;

remove this line.

@@ +282,5 @@
> +
> +    let le = -1;
> +    let dataLen = -1;
> +    let offset = 0;
> +    let apduFieldsLen = 4; // (CLA + INS + P1 + P2)

Can we merge 'offset' and apduFieldsLen' into one variable?

@@ +283,5 @@
> +    let le = -1;
> +    let dataLen = -1;
> +    let offset = 0;
> +    let apduFieldsLen = 4; // (CLA + INS + P1 + P2)
> +    dataLen = !command.data ? 0 : command.data.length;

more straightforward.

let dataLen = command.data ? command.data.length : 0;

@@ +292,5 @@
> +      le = command.le;
> +      apduFieldsLen++; // Le
> +    }
> +
> +    if ((apduFieldsLen + dataLen) > SE.MAX_APDU_LEN)

nit, add {}

@@ +311,5 @@
> +      }
> +    }
> +    if (le !== -1) {
> +      apduCommand[offset] = command.le;
> +    }

I think you should move these code to a helper that coverts SECommand to a TypedArray.

@@ +321,5 @@
> +                              apdu: apduCommand,
> +                              channelToken: this._channelToken,
> +                              aid: this._aid,
> +                              sessionId: this._sessionId,
> +                              appId: this._window.document.nodePrincipal.appId

Please explain why are these parameters for.

@@ +361,5 @@
> +    return ['basic', 'logical'][type];
> +  },
> +
> +  _checkClosed: function() {
> +    if (this.isClosed === true) {

When will this.isClosed be set to true?

@@ +373,5 @@
> + * SESession
> + * ==============================================
> + */
> +
> +function SESession(aSessionInfo) {

Please move these implementations by order.
SEReader, SESesssion, SEChannel.

@@ +392,5 @@
> +
> +  openBasicChannel: function(aid) {
> +    // Not Supported for now!
> +    return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> +      "OpenBasicChannel() is not supported for SE type : " + SE.TYPE_UICC);

Should only reject when the type of READER is of UICC,
not reject directly.
Or if not supported for now, remove it.

@@ +401,5 @@
> +    // According to SIMalliance_OpenMobileAPI v3 draft:
> +    // In case of UICC it is recommended to reject the opening of the logical
> +    // channel without a specific AID.
> +    if (!aid || aid.length === 0) {
> +      if (this.reader.type === SE.TYPE_UICC)

if (this.reader.type == UICC) should be moved to outter.

@@ +406,5 @@
> +        return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> +                                                  "AID is not specified!");
> +    }
> +
> +    if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN)

nit, {}

@@ +407,5 @@
> +                                                  "AID is not specified!");
> +    }
> +
> +    if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN)
> +      return PromiseHelpers._rejectWithSEError('SEGenericError: ' +

use double quotes.

@@ +410,5 @@
> +    if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN)
> +      return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> +                                               "Invalid AID length - " + aid.length);
> +
> +    this._aid = Cu.waiveXrays(aid);

Why does we need waiveXrays here?

@@ +444,5 @@
> +                                });
> +  },
> +
> +  get atr() {
> +    // 'Answer to Reset' is not supported for now, return null.

remove it.
Add this when you plan to implement it.

@@ +499,5 @@
> +    });
> +  },
> +
> +  get isSEPresent() {
> +    return cpmm.sendSyncMessage("SE:CheckSEState",

Sync?

@@ +527,5 @@
> +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
> +                                         Ci.nsISupportsWeakReference,
> +                                         Ci.nsIObserver]),
> +
> +  init: function SEManagerInit(win) {

another style of function name.

@@ +530,5 @@
> +
> +  init: function SEManagerInit(win) {
> +    this._window = win;
> +    PromiseHelpers = new PromiseHelpersSubclass(this._window);
> +    this.innerWindowID = win.QueryInterface(Ci.nsIInterfaceRequestor)

What's this for?

@@ +539,5 @@
> +    let perm = Services.perms.testExactPermissionFromPrincipal(principal,
> +                                                               "secureelement-manage");
> +    if (perm === Ci.nsIPermissionManager.ALLOW_ACTION) {
> +      this._isAllowed = true;
> +    }

I think WebIDL bindings could do this check for you.

@@ +543,5 @@
> +    }
> +
> +    // Add the messages to be listened to.
> +    const messages = ["SE:GetSEReadersResolved",
> +                      "SE:OpenSessionResolved",

Why cannt we merge OpenSessionResolved and OpenSessionRejected into one message?

@@ +567,5 @@
> +     PromiseHelpers = null;
> +     this._window = null;
> +  },
> +
> +  _ensureAccess: function() {

Who calls this function?

@@ +592,5 @@
> +  receiveMessage: function(aMessage) {
> +    let data = aMessage.json;
> +    let chromeObj = null;
> +    let contentObj = null;
> +    debug("receiveMessage(): " + aMessage.name + " " + JSON.stringify(data));

Don't use JSON.stringify.

@@ +601,5 @@
> +    }
> +
> +    switch (aMessage.name) {
> +      case "SE:GetSEReadersResolved":
> +        let availableReaders = this._window.Array();

[];
Attachment #8533057 - Flags: review?(allstars.chh) → review-
Comment on attachment 8533065 [details] [diff] [review]
Patch 3: (v3.1) Secure Element Parent process Implementation. r=yoshi

Review of attachment 8533065 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/system/gonk/SecureElement.js
@@ +21,5 @@
> +
> +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
> +Cu.import("resource://gre/modules/Services.jsm");
> +Cu.import("resource://gre/modules/systemlibs.js");
> +Cu.import("resource://gre/modules/Promise.jsm");

Why is this for?

@@ +22,5 @@
> +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
> +Cu.import("resource://gre/modules/Services.jsm");
> +Cu.import("resource://gre/modules/systemlibs.js");
> +Cu.import("resource://gre/modules/Promise.jsm");
> +Cu.import("resource://gre/modules/FileUtils.jsm");

this too.

@@ +56,5 @@
> +
> +function debug(s) {
> +  if (DEBUG) {
> +    dump("-*- SecureElement: " + s + "\n");
> +  }

debug should be moved to the top.

@@ +82,5 @@
> +  gSEMessageManager.init(this);
> +}
> +
> +SecureElement.prototype = {
> +

nit, extra line.

@@ +84,5 @@
> +
> +SecureElement.prototype = {
> +
> +  classID: SE_CID,
> +  classInfo: XPCOMUtils.generateCI({classID: SE_CID,

nit, I prefer to move classID to next line, so every property starts at the same position.

@@ +98,5 @@
> +
> +  observe: function(subject, topic, data) {
> +    switch (topic) {
> +      case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
> +      Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);

indent
also this function does NOTHING.
You plan to call some shutdown function ?

@@ +106,5 @@
> +};
> +
> +XPCOMUtils.defineLazyGetter(this, "gSEMessageManager", function() {
> +  return {
> +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,

indent, all properties should be indented.

return {
  QueryInterface: ...,
};

Ci.nsIMessageListener should be moved to next line.
Comment on attachment 8533065 [details] [diff] [review]
Patch 3: (v3.1) Secure Element Parent process Implementation. r=yoshi

Review of attachment 8533065 [details] [diff] [review]:
-----------------------------------------------------------------

I'll stop in the middle as I find out this patch is hard to know what's going on and hard for review.
Please consider using more abstractions here, or maybe some IDL, or more documentations.

Please make your code more modularized.
Most code should be moved into SecureManager, however they are located in gSEMessageManager.
All functions are prefix with _, which means private.

Please make those related functions together.

Like

// Impl for SEReader
...

// Impl for SESession
...

// Impl for SEChannel.
...

And above functions should not prefix with _

only prefix _ with some helper functions.

Or using '_' more appropriately.  Using it in all functions is the same thing as not using it at all.

Also there should be some nsISecureElement idl, so RIL part, NFC part could implement this interface.
And SecureElement should call that interface accordingly with the reader type.

::: dom/system/gonk/SecureElement.js
@@ +108,5 @@
> +XPCOMUtils.defineLazyGetter(this, "gSEMessageManager", function() {
> +  return {
> +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
> +                       Ci.nsIObserver,
> +                       Ci.nsIIccListener]),

IccListener should be implemented by some object that implements SecureElement.
You're making this 'gSEMessageManager' more complicated for what it is doing here.

@@ +172,5 @@
> +                                      }
> +                        } ]
> +       ]
> +     }
> +  */

please indent this, it's hard to read this.

@@ +175,5 @@
> +     }
> +  */
> +  appInfoMap: {},
> +
> +  cardReady: null,

I think you mean 'isSEPresent'.

But this attribute should be moved to some nsISecureElement, which could be implemented by ICC or EmbeddedSE.

@@ +209,5 @@
> +    }
> +    ppmm = null;
> +  },
> +
> +  _initializeSEListeners: function() {

This should not be done in here. (gSEMessageManager).

@@ +220,5 @@
> +    // Detach the listener to UICC state changes
> +    iccProvider.unregisterIccMsg(PREFERRED_UICC_CLIENTID, this);
> +  },
> +
> +  _registerSETarget: function(message, readers) {

I don't understand what's this for and what's the purpose of storing target here.

@@ +256,5 @@
> +      }
> +    }
> +  },
> +
> +  _removeAllSessions: function(msg) {

This should NOT be defined here.

@@ +259,5 @@
> +
> +  _removeAllSessions: function(msg) {
> +    let allSessions = this.appInfoMap[msg.appId].sessions;
> +    // reset all sessions
> +    if (allSessions)

the if check makes non-sense here.
in line 236 you already allocate it as an plain object.

@@ +278,5 @@
> +  },
> +
> +  _removeSession: function(msg) {
> +    let sessions = this.appInfoMap[msg.appId].sessions;
> +    if (sessions && sessions[msg.sessionId].type === msg.type)

'sessions' check seems not neccesary, as it initializes as a plain object.
Or you have to refactor your data structure.

@@ +284,5 @@
> +  },
> +
> +  _addChannel: function(channelInfo, msg) {
> +    let appId = msg.appId;
> +    let token = channelInfo.token;

What does a token mean?

Or you're refering to some ChannelID?

@@ +364,5 @@
> +    }); // End of AppId keys
> +    debug("----------------------------------------------------------------------------------------");
> +  },
> +*/
> +  _isChannelRegistered: function(channel, msg) {

Who calls this?

@@ +664,5 @@
> +    let cla = apduCmd[SE.CLA_BYTE_OFFSET] & 0xFF;
> +    let ins = apduCmd[SE.INS_BYTE_OFFSET] & 0xFF;
> +    let p1 = apduCmd[SE.P1_BYTE_OFFSET] & 0xFF;
> +    let p2 = apduCmd[SE.P2_BYTE_OFFSET] & 0xFF;
> +    let p3 = !apduCmd[SE.P3_BYTE_OFFSET] ? 0 : apduCmd[SE.P3_BYTE_OFFSET] & 0xFF;

In Content side you should just pass an object 
{
  cla: ...,
  ins: ..
};

so you don't have to encode/decode it as TypedArray twice.

@@ +831,5 @@
> +    let cardState = iccProvider.getCardState(PREFERRED_UICC_CLIENTID);
> +    return (((cardState !== null) && (notReadyStates.indexOf(cardState) == -1)) ? true : false);
> +  },
> +
> +  _checkAndRetrieveAvailableReaders: function() {

this method should query modules that implements nsISecureElement.
And if SE is not present, should we return the reader?

For example, if SIM is not inserted, or in AirPlane mode, should we return reader of ICC?
Attachment #8533065 - Flags: review?(allstars.chh) → review-
(Assignee)

Comment 130

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #129)
> Comment on attachment 8533065 [details] [diff] [review]
> Patch 3: (v3.1) Secure Element Parent process Implementation. r=yoshi
> 
> Review of attachment 8533065 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> I'll stop in the middle as I find out this patch is hard to know what's
> going on and hard for review.
> Please consider using more abstractions here, or maybe some IDL, or more
> documentations.
> 
> Please make your code more modularized.
> Most code should be moved into SecureManager, however they are located in
> gSEMessageManager.

Thanks for your feedback. I was half way through making Parent process more modular when I uploaded these patches. Hopefully I should have something for your review again in next couple of days. Please treat this as acknowledgement to all your comments thus far. I will ping you on IRC for clarifications if any.

> All functions are prefix with _, which means private.
> 
> Please make those related functions together.
> 
> Like
> 
> // Impl for SEReader
> ...
> 
> // Impl for SESession
> ...
> 
> // Impl for SEChannel.
> ...
> 
> And above functions should not prefix with _
> 
> only prefix _ with some helper functions.
> 
> Or using '_' more appropriately.  Using it in all functions is the same
> thing as not using it at all.
> 
> Also there should be some nsISecureElement idl, so RIL part, NFC part could
> implement this interface.
> And SecureElement should call that interface accordingly with the reader
> type.
> 
> ::: dom/system/gonk/SecureElement.js
> @@ +108,5 @@
> > +XPCOMUtils.defineLazyGetter(this, "gSEMessageManager", function() {
> > +  return {
> > +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
> > +                       Ci.nsIObserver,
> > +                       Ci.nsIIccListener]),
> 
> IccListener should be implemented by some object that implements
> SecureElement.
> You're making this 'gSEMessageManager' more complicated for what it is doing
> here.
> 
> @@ +172,5 @@
> > +                                      }
> > +                        } ]
> > +       ]
> > +     }
> > +  */
> 
> please indent this, it's hard to read this.
> 
> @@ +175,5 @@
> > +     }
> > +  */
> > +  appInfoMap: {},
> > +
> > +  cardReady: null,
> 
> I think you mean 'isSEPresent'.
> 
> But this attribute should be moved to some nsISecureElement, which could be
> implemented by ICC or EmbeddedSE.
> 
> @@ +209,5 @@
> > +    }
> > +    ppmm = null;
> > +  },
> > +
> > +  _initializeSEListeners: function() {
> 
> This should not be done in here. (gSEMessageManager).
> 
> @@ +220,5 @@
> > +    // Detach the listener to UICC state changes
> > +    iccProvider.unregisterIccMsg(PREFERRED_UICC_CLIENTID, this);
> > +  },
> > +
> > +  _registerSETarget: function(message, readers) {
> 
> I don't understand what's this for and what's the purpose of storing target
> here.
> 
> @@ +256,5 @@
> > +      }
> > +    }
> > +  },
> > +
> > +  _removeAllSessions: function(msg) {
> 
> This should NOT be defined here.
> 
> @@ +259,5 @@
> > +
> > +  _removeAllSessions: function(msg) {
> > +    let allSessions = this.appInfoMap[msg.appId].sessions;
> > +    // reset all sessions
> > +    if (allSessions)
> 
> the if check makes non-sense here.
> in line 236 you already allocate it as an plain object.
> 
> @@ +278,5 @@
> > +  },
> > +
> > +  _removeSession: function(msg) {
> > +    let sessions = this.appInfoMap[msg.appId].sessions;
> > +    if (sessions && sessions[msg.sessionId].type === msg.type)
> 
> 'sessions' check seems not neccesary, as it initializes as a plain object.
> Or you have to refactor your data structure.
> 
> @@ +284,5 @@
> > +  },
> > +
> > +  _addChannel: function(channelInfo, msg) {
> > +    let appId = msg.appId;
> > +    let token = channelInfo.token;
> 
> What does a token mean?
> 
> Or you're refering to some ChannelID?
> 
> @@ +364,5 @@
> > +    }); // End of AppId keys
> > +    debug("----------------------------------------------------------------------------------------");
> > +  },
> > +*/
> > +  _isChannelRegistered: function(channel, msg) {
> 
> Who calls this?
> 
> @@ +664,5 @@
> > +    let cla = apduCmd[SE.CLA_BYTE_OFFSET] & 0xFF;
> > +    let ins = apduCmd[SE.INS_BYTE_OFFSET] & 0xFF;
> > +    let p1 = apduCmd[SE.P1_BYTE_OFFSET] & 0xFF;
> > +    let p2 = apduCmd[SE.P2_BYTE_OFFSET] & 0xFF;
> > +    let p3 = !apduCmd[SE.P3_BYTE_OFFSET] ? 0 : apduCmd[SE.P3_BYTE_OFFSET] & 0xFF;
> 
> In Content side you should just pass an object 
> {
>   cla: ...,
>   ins: ..
> };
> 
> so you don't have to encode/decode it as TypedArray twice.
> 
> @@ +831,5 @@
> > +    let cardState = iccProvider.getCardState(PREFERRED_UICC_CLIENTID);
> > +    return (((cardState !== null) && (notReadyStates.indexOf(cardState) == -1)) ? true : false);
> > +  },
> > +
> > +  _checkAndRetrieveAvailableReaders: function() {
> 
> this method should query modules that implements nsISecureElement.
> And if SE is not present, should we return the reader?
> 
> For example, if SIM is not inserted, or in AirPlane mode, should we return
> reader of ICC?
Comment on attachment 8533068 [details] [diff] [review]
Patch 4: (v4.1) Add new permission to table - 'secureelement-manage'

Review of attachment 8533068 [details] [diff] [review]:
-----------------------------------------------------------------

This should go with Part 1.
Attachment #8533068 - Flags: review?(allstars.chh)
Comment on attachment 8533051 [details] [diff] [review]
Patch 1 : (v1.10) Secure Element APIs - Inital Draft

Review of attachment 8533051 [details] [diff] [review]:
-----------------------------------------------------------------

*Please* submit interdiffs next time.  Thanks!

::: dom/webidl/SecureElement.webidl
@@ +109,5 @@
> +  // 'session' obj this channel is bound to
> +  readonly attribute SESession session;
> +
> +  // response to openBasicChannel / openLogicalChannel operation
> +  [Constant, Cached] readonly  attribute Uint8Array? openResponse;

I can't see why this should be [Constant, Cached]?
Attachment #8533051 - Flags: review?(ehsan.akhgari) → review+
(Assignee)

Comment 133

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #129)
> Comment on attachment 8533065 [details] [diff] [review]
> Patch 3: (v3.1) Secure Element Parent process Implementation. r=yoshi
> 
> Review of attachment 8533065 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> I'll stop in the middle as I find out this patch is hard to know what's
> going on and hard for review.
> Please consider using more abstractions here, or maybe some IDL, or more
> documentations.
> 
> Please make your code more modularized.
> Most code should be moved into SecureManager, however they are located in
> gSEMessageManager.
In the latest refactored patch, it has mainly 3 objects.
gMap , gSecureElementManager, SEConnectorFactory that gets the instance of Connector obj ('UiccConnector say) based on type ('uicc' / 'eSE').
Only the main object 'gSecureElementManager' which also acts as MessageManager talks to both 'gMap' and 'SEConnector obj'. 'gMap' and  'UiccConnector' doesn't have to talk to each other.
> All functions are prefix with _, which means private.
I think I have now made that differentiation in the latest patch.
> Please make those related functions together.
> 
> Like
> 
> // Impl for SEReader
> ...
> 
> // Impl for SESession
> ...
> 
> // Impl for SEChannel.
> ...
> 
> And above functions should not prefix with _
> 
> only prefix _ with some helper functions.
> 
> Or using '_' more appropriately.  Using it in all functions is the same
> thing as not using it at all.
> 
> Also there should be some nsISecureElement idl, so RIL part, NFC part could
> implement this interface.
> And SecureElement should call that interface accordingly with the reader
> type.
> 
As discussed on IRC, though this is not implemented, this information needed is abstracted in 'UiccConnector' obj. It listens to uicc state changes by implementing 'nsIIccListener' interface.

> ::: dom/system/gonk/SecureElement.js
> @@ +108,5 @@
> > +XPCOMUtils.defineLazyGetter(this, "gSEMessageManager", function() {
> > +  return {
> > +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
> > +                       Ci.nsIObserver,
> > +                       Ci.nsIIccListener]),
> 
> IccListener should be implemented by some object that implements
> SecureElement.
> You're making this 'gSEMessageManager' more complicated for what it is doing
> here.
> 
> @@ +172,5 @@
> > +                                      }
> > +                        } ]
> > +       ]
> > +     }
> > +  */
> 
> please indent this, it's hard to read this.
> 
> @@ +175,5 @@
> > +     }
> > +  */
> > +  appInfoMap: {},
> > +
> > +  cardReady: null,
> 
> I think you mean 'isSEPresent'.
> 
> But this attribute should be moved to some nsISecureElement, which could be
> implemented by ICC or EmbeddedSE.
> 
> @@ +209,5 @@
> > +    }
> > +    ppmm = null;
> > +  },
> > +
> > +  _initializeSEListeners: function() {
> 
> This should not be done in here. (gSEMessageManager).
> 
> @@ +220,5 @@
> > +    // Detach the listener to UICC state changes
> > +    iccProvider.unregisterIccMsg(PREFERRED_UICC_CLIENTID, this);
> > +  },
> > +
> > +  _registerSETarget: function(message, readers) {
> 
> I don't understand what's this for and what's the purpose of storing target
> here.
> 
As per open mobile spec, each application when registering shall be checked against possible readerTypes (ex: 'uicc' (or) 'eSE') that it has permissions to connect to. A certain wallet app can only have access to 'uicc' readerType and not to 'eSE'. Though this kind of enforcement doesn't happen in the existing patch, this may give us flexibility  to do the same when multiple secure-elements are supported.
> @@ +256,5 @@
> > +      }
> > +    }
> > +  },
> > +
> > +  _removeAllSessions: function(msg) {
> 
> This should NOT be defined here.
> 
> @@ +259,5 @@
> > +
> > +  _removeAllSessions: function(msg) {
> > +    let allSessions = this.appInfoMap[msg.appId].sessions;
> > +    // reset all sessions
> > +    if (allSessions)
> 
> the if check makes non-sense here.
> in line 236 you already allocate it as an plain object.
> 
There could be a possibility of 'msg.appId' not present in appInfoMap . In that case, this.appInfoMap[msg.appId] will become 'undefined' . Isn't ? I think if check ensures against such behavior that may break JS engine.
Also since this 'appId' is coming from Content , it acts as another check anyways. What do you think ?
> @@ +278,5 @@
> > +  },
> > +
> > +  _removeSession: function(msg) {
> > +    let sessions = this.appInfoMap[msg.appId].sessions;
> > +    if (sessions && sessions[msg.sessionId].type === msg.type)
> 
> 'sessions' check seems not neccesary, as it initializes as a plain object.
> Or you have to refactor your data structure.
> 
Ok. removed 'sessions' now
> @@ +284,5 @@
> > +  },
> > +
> > +  _addChannel: function(channelInfo, msg) {
> > +    let appId = msg.appId;
> > +    let token = channelInfo.token;
> 
> What does a token mean?
> 
> Or you're refering to some ChannelID?
'token' here refers to 'channelToken'. On opening a channel, say, channel# '2' is returned by RIL stack. This  information is kept in parent process while only a unique uuid (token) is sent to DOM. For any further operations on this channel (#2), DOM content target should always pass this 'token' to parent process for validation. This 'token' however is not exposed to Gaia apps
> 
> @@ +364,5 @@
> > +    }); // End of AppId keys
> > +    debug("----------------------------------------------------------------------------------------");
> > +  },
> > +*/
> > +  _isChannelRegistered: function(channel, msg) {
> 
> Who calls this?
> 
Removed this now.
> @@ +664,5 @@
> > +    let cla = apduCmd[SE.CLA_BYTE_OFFSET] & 0xFF;
> > +    let ins = apduCmd[SE.INS_BYTE_OFFSET] & 0xFF;
> > +    let p1 = apduCmd[SE.P1_BYTE_OFFSET] & 0xFF;
> > +    let p2 = apduCmd[SE.P2_BYTE_OFFSET] & 0xFF;
> > +    let p3 = !apduCmd[SE.P3_BYTE_OFFSET] ? 0 : apduCmd[SE.P3_BYTE_OFFSET] & 0xFF;
> 
> In Content side you should just pass an object 
> {
>   cla: ...,
>   ins: ..
> };
> 
> so you don't have to encode/decode it as TypedArray twice.
> 
Agreed.
> @@ +831,5 @@
> > +    let cardState = iccProvider.getCardState(PREFERRED_UICC_CLIENTID);
> > +    return (((cardState !== null) && (notReadyStates.indexOf(cardState) == -1)) ? true : false);
> > +  },
> > +
> > +  _checkAndRetrieveAvailableReaders: function() {
> 
> this method should query modules that implements nsISecureElement.
> And if SE is not present, should we return the reader?
> 
Based on our IRC discussion, I hope you are ok with the latest changes.

> For example, if SIM is not inserted, or in AirPlane mode, should we return
> reader of ICC?
I think we should still return the 'reader' in Airplane mode. If it is not inserted, then as per current design, we will not return 'uicc' based reader to DOM .

Please note that I am only uploading Parent process (Patch#3) changes for now. DOM changes will soon follow this. Thanks for your time.
(Assignee)

Comment 134

3 years ago
Created attachment 8536941 [details] [diff] [review]
Part 3: (v3.2) Secure Element Parent process Implementation. r=yoshi
Attachment #8533065 - Attachment is obsolete: true
Attachment #8536941 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 135

3 years ago
Created attachment 8536977 [details] [diff] [review]
Part 3: (v3.2) Secure Element Parent process Implementation. r=yoshi
Attachment #8536941 - Attachment is obsolete: true
Attachment #8536941 - Flags: feedback?(allstars.chh)
Attachment #8536977 - Flags: feedback?(allstars.chh)
(Assignee)

Comment 136

3 years ago
(In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!) from comment #132)
> Comment on attachment 8533051 [details] [diff] [review]
> Patch 1 : (v1.10) Secure Element APIs - Inital Draft
> 
> Review of attachment 8533051 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> *Please* submit interdiffs next time.  Thanks!
> 
> ::: dom/webidl/SecureElement.webidl
> @@ +109,5 @@
> > +  // 'session' obj this channel is bound to
> > +  readonly attribute SESession session;
> > +
> > +  // response to openBasicChannel / openLogicalChannel operation
> > +  [Constant, Cached] readonly  attribute Uint8Array? openResponse;
> 
> I can't see why this should be [Constant, Cached]?

I am not sure if I have interpreted these attributes correctly. Per MDN,
"Used to flag attributes that, when their getter is called, will cache the returned value on the JS object.  This can be used to implement attributes whose value is a sequence or dictionary (which would otherwise end up returning a new object each time and hence not be allowed in WebIDL)." 
In order to avoid creation of 'new object' every-time it is called by Gaia apps. Also as  [Cached] attributes must be [Pure] or [Constant], I chose [Constant] because it can return the same value every-time.
(In reply to Siddartha P from comment #133)
> (In reply to Yoshi Huang[:allstars.chh] from comment #129)
> As per open mobile spec, each application when registering shall be checked
> against possible readerTypes (ex: 'uicc' (or) 'eSE') that it has permissions
> to connect to. A certain wallet app can only have access to 'uicc'
> readerType and not to 'eSE'. Though this kind of enforcement doesn't happen
> in the existing patch, 
Remove this and file another bug for this.
Please don't add any code which won't be executed in this version.
Or implement it.

And please file follow-up bugs you plan to fix and add them in the TODO in your patch.
Comment on attachment 8536977 [details] [diff] [review]
Part 3: (v3.2) Secure Element Parent process Implementation. r=yoshi

Review of attachment 8536977 [details] [diff] [review]:
-----------------------------------------------------------------

Why are these files in dom/system/gonk?
Shouldn't these be located in dom/secureelement/gonk?

Also I still didn't review the gMap part as I asked to indent it last time.
But it's still the way it's.

::: dom/system/gonk/SecureElement.js
@@ +57,5 @@
> +  "SE:GetChannelType",
> +  "SE:IsChannelClosed"
> +];
> +
> +const SE_CONTRACTID = "@mozilla.org/se;1";

use full name for se.

@@ +85,5 @@
> +    classID: SE_CID,
> +    contractID: SE_CONTRACTID,
> +    classDescription: "SecureElement",
> +    interfaces: []})
> +};

What is this SecureElement for actually?

@@ +91,5 @@
> +// Factory constructor
> +function SEConnectorFactory() {}
> +
> +/**
> + * Factory like pattern for getting the Connector obj.

What's a 'Connector' object?
and what's the difference between it and SecureElement?

@@ +103,5 @@
> +SEConnectorFactory.prototype = {
> +
> +  connectorClass: null,
> +
> +  get: function(options) {

get what? 

for the argument, use 'type' directly.

@@ +109,5 @@
> +      case SE.TYPE_ESE:
> +        if (DEBUG) debug('UnSupported SEConnector : ' + SE.TYPE_ESE);
> +        break;
> +      case SE.TYPE_UICC:
> +      default: // Default ConnectorClass is UiccConnector

Why Uicc is default?

@@ +113,5 @@
> +      default: // Default ConnectorClass is UiccConnector
> +        this.connectorClass = UiccConnector;
> +        break;
> +    }
> +    return this.connectorClass;

connectorClass seems useless.

switch (type) {
  case ESE:
    return null;
  case UICC:
    return UiccConnector;
}

@@ +190,5 @@
> +                 ...
> +                 ...
> +                 ...
> +       ]
> +    } */

indent this, or I won't be able to review this.

@@ +439,5 @@
> +    isChannelClosed: function(data) {
> +      return !this.appInfoMap[data.appId].sessions[data.sessionId].channels[data.channelToken];
> +    },
> +
> +

extra line.

@@ +464,5 @@
> +     * Private internal functions
> +     */
> +
> +    // Retrieves all the channels for the given 'channels' object
> +    _getChannels: function(channels) {

Make it more easier to understand.

@@ +468,5 @@
> +    _getChannels: function(channels) {
> +      if (!channels)
> +        return null;
> +
> +      let channelNumbers = new Array();

[]

@@ +526,5 @@
> +XPCOMUtils.defineLazyGetter(this, "UiccConnector", function() {
> +  return {
> +    QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccListener]),
> +
> +    _isUiccSecureElementPresent: false,

using shorter name

@@ +545,5 @@
> +    notifyIccInfoChanged: function() {},
> +
> +    // This function acts as a trigger to listen on 'nsIIccListener' callbacks
> +    start: function() {
> +      if (DEBUG) debug("Default Client ID " + PREFERRED_UICC_CLIENTID);

remove this line.

@@ +566,5 @@
> +    doOpenChannel: function(aid, callback) {
> +      if (!aid || aid.length === 0) {
> +        // According to SIMalliance_OpenMobileAPI v3 draft,
> +        // it is recommended not to support it.
> +        debug('AID is not set. Reject the openChannel request!');

use double quote.

@@ +570,5 @@
> +        debug('AID is not set. Reject the openChannel request!');
> +        throw new Error(SE.ERROR_SECURITY);
> +      }
> +
> +      if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {

let aidLen = aid ? aid.length : 0;

then you can merge these two if checks.

Also I think this check should be done in DOM part.

@@ +602,5 @@
> +    doTransmit: function(command, callback) {
> +      let cla = command.cla & 0xFF;
> +      let ins = command.ins & 0xFF;
> +      let p1 = command.p1 & 0xFF;
> +      let p2 = command.p2 & 0xFF;

Is these & 0xff neccesary?
If you have defined your WebIDL well, these should be done already.

@@ +619,5 @@
> +      }
> +      else if (command.le !== -1) {
> +        // Only le is set. 'p3=le'. Response expected!
> +        p3 = command.le;
> +      }

let p3 = command.data ?
           commmand.data.length : 
           (command.le != -1 ? command.le : 0x00);
let appendLe = (command.data != null) && (command.le != -1);

@@ +622,5 @@
> +        p3 = command.le;
> +      }
> +
> +      // At this point perform more sanity checks on the c-apdu
> +      if (p3 + SE.APDU_HEADER_LEN > SE.MAX_APDU_LEN) {

Do this in Content?

@@ +635,5 @@
> +          typeof command.p1 === 'undefined' ||
> +          typeof command.p2 === 'undefined') {
> +        debug('Mandatory command headers Missing! - Invalid Command');
> +        throw new Error(SE.ERROR_IO);
> +      }

Shouldn't this be done in Content side?

@@ +651,5 @@
> +        }
> +        if (DEBUG) debug("Attempting to transmit an ISO command");
> +      } else {
> +        if (DEBUG) debug("Attempting to transmit GlobalPlatform command");
> +      }

done in content ?

@@ +674,5 @@
> +        let leHexStr = SE.gUtils.byteTohexString(le & 0xFF) +
> +                       SE.gUtils.byteTohexString((le >> 8) & 0xFF) ;
> +        data += leHexStr;
> +      }
> +      let channel = this._getChannelNumber(cla & 0xFF);

you already & 0xff in the beginning of this function.

@@ +702,5 @@
> +      // TBD: Finally Perform checks with ACE module
> +
> +      let count = 0;
> +      for (let index = 0; index < channels.length; index++) {
> +        let channelNumber = channels[index];

Can't we just call it 'channel'? Why 'channelNumber' ?

@@ +703,5 @@
> +
> +      let count = 0;
> +      for (let index = 0; index < channels.length; index++) {
> +        let channelNumber = channels[index];
> +        if (channelNumber === SE.TYPE_BASIC_CHANNEL) {

This looks totally confusing.
if this is a type, then it should be named 'channelType'. Also same for the channels.

@@ +847,5 @@
> +        "personalizationInProgress",
> +        "permanentBlocked"
> +      ];
> +      let cardState = iccProvider.getCardState(PREFERRED_UICC_CLIENTID);
> +      return (((cardState !== null) && (notReadyStates.indexOf(cardState) == -1)) ? true : false);

can't we just compare cardState to CARD_STATE_READY?

@@ +861,5 @@
> + * It mainly interacts with 'gMap' to query the state of Readers, Sessions, Channels,
> + * while it interacts with 'Connector instances' to perform low level SE-related
> + * (open,close,transmit) I/O operations.
> + */
> +XPCOMUtils.defineLazyGetter(this, "gSecureElementManager", function() {

I don't think this should be a lazy getter.

@@ +876,5 @@
> +      Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
> +      this._registerMessageListeners();
> +      // This is needed for UiccConnector to start listening on uicc state changes
> +      UiccConnector.start();
> +      this.connectorFactory = new SEConnectorFactory();

Given that you have ConnectorFactory, you should access UiccConnector through that factory.
Otherwise your 'factory' will be useless.

@@ +1070,5 @@
> +     */
> +
> +    receiveMessage: function(msg) {
> +      if (DEBUG) debug("Received '" + msg.name + "' message from content process" + ": " +
> +                       JSON.stringify(msg.json));

use msg.data

@@ +1075,5 @@
> +      let status = SE.ERROR_GENERIC;
> +      let message = msg;
> +      let promiseStatus = "Rejected";
> +      let options = { status: status,
> +                                 resolverId: msg.json ? msg.json.resolverId : null };

align.

@@ +1184,5 @@
> +          return gMap.isSessionClosed(msg.json);
> +        case "SE:GetChannelType":
> +          return gMap.getChannelType(msg.json);
> +        case "SE:IsChannelClosed":
> +          return gMap.isChannelClosed(msg.json);

That should be some notifications back to the DOM part, like notifySEPresent, notifSessionClosed, notifyChannelClosed, ... etc,
so these getters could be done in DOM layer.

@@ +1187,5 @@
> +        case "SE:IsChannelClosed":
> +          return gMap.isChannelClosed(msg.json);
> +        default:
> +          throw new Error("Don't know about this message: " + msg.name);
> +          return;

You already did this check in line 1095

@@ +1189,5 @@
> +        default:
> +          throw new Error("Don't know about this message: " + msg.name);
> +          return;
> +      }
> +      msg.target.sendAsyncMessage(msg.name + promiseStatus, options);

move this line into cases, like GetSEReaders, OpenSession.

@@ +1206,5 @@
> +    }
> +  };
> +});
> +
> +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SecureElement]);

Seems to me you should put SecureElementManager here.

::: dom/system/gonk/moz.build
@@ +100,5 @@
> +    'SecureElement.js',
> +    'SecureElement.manifest',
> +]
> +EXTRA_JS_MODULES += [
> +        'se_consts.js',

indent.

Also this should be moved to somewhere like dom/secureelement/gonk

::: dom/system/gonk/se_consts.js
@@ +15,5 @@
> +
> +/* Copyright © 2014, Deutsche Telekom, Inc. */
> +
> +// Set to true to debug SecureElement (SE) stack
> +this.DEBUG_ALL = true;

default to false.

@@ +18,5 @@
> +// Set to true to debug SecureElement (SE) stack
> +this.DEBUG_ALL = true;
> +
> +// Set individually to debug specific layers
> +this.DEBUG_ACE = false || DEBUG_ALL;

?
remove this.

@@ +19,5 @@
> +this.DEBUG_ALL = true;
> +
> +// Set individually to debug specific layers
> +this.DEBUG_ACE = false || DEBUG_ALL;
> +this.DEBUG_SE = false || DEBUG_ALL;

reverse the order.

DEBUG_ALL || false;

@@ +24,5 @@
> +
> +// Ideally this should have been 3, as we do not allow basic channel' : 0 on 'uicc'.
> +// Max number of supplementary logical channels available would be : [1, 2, or 3].
> +// Other SE types may support upto max 4.
> +

extra line.

@@ +29,5 @@
> +// Maximun logical channels per session.
> +this.MAX_CHANNELS_ALLOWED_PER_SESSION = 4;
> +
> +this.TYPE_BASIC_CHANNEL = 0;
> +this.TYPE_LOGICAL_CHANNEL = 1;

Seems boolean is enough.

@@ +61,5 @@
> +this.ERROR_IO                 = 'SEIoError';
> +this.ERROR_BADSTATE           = 'SEBadStateError';
> +this.ERROR_INVALIDCHANNEL     = 'SEInvalidChannelError';
> +this.ERROR_INVALIDAPPLICATION = 'SEInvalidApplicationError';
> +this.ERROR_GENERIC            = 'SEGenericError';

double quotes.

@@ +64,5 @@
> +this.ERROR_INVALIDAPPLICATION = 'SEInvalidApplicationError';
> +this.ERROR_GENERIC            = 'SEGenericError';
> +
> +this.TYPE_UICC = 'uicc';
> +this.TYPE_ESE = 'eSE';

ditto.

@@ +66,5 @@
> +
> +this.TYPE_UICC = 'uicc';
> +this.TYPE_ESE = 'eSE';
> +
> +this.gUtils = {

move this to a JSM, and these functions should have tests.

@@ +67,5 @@
> +this.TYPE_UICC = 'uicc';
> +this.TYPE_ESE = 'eSE';
> +
> +this.gUtils = {
> +  hexStringToBytes: function(hexString) {

hexStringToByteArray

@@ +69,5 @@
> +
> +this.gUtils = {
> +  hexStringToBytes: function(hexString) {
> +    let bytes = [];
> +    let length = hexString.length;

what if hexString is null or undefined?

@@ +78,5 @@
> +
> +    return bytes;
> +  },
> +
> +  byteTohexString: function(array) {

byteArrayToHexString
and using the same naming, 'array' or 'bytes'.

@@ +80,5 @@
> +  },
> +
> +  byteTohexString: function(array) {
> +    let hexString = "";
> +    let hex;

move hex into for loop.

@@ +83,5 @@
> +    let hexString = "";
> +    let hex;
> +
> +    if (!array || array.length === 0)
> +      return hexString;

let length = array ? array.length : 0;

for (let i = 0; i < length; i++)

then the if check can be removed now.

@@ +86,5 @@
> +    if (!array || array.length === 0)
> +      return hexString;
> +
> +    for (let i = 0; i < array.length; i++) {
> +      hex = array[i].toString(16).toUpperCase();

If you want upperCase, do it in the return.

return hexString.toUpperCase();
Attachment #8536977 - Flags: feedback?(allstars.chh) → review-
I still there are still some patches missing,
like b2g/installer/package-manifest.in
configure.in
dom/moz.build

Please check what you did in WebNFC and add the missing patches back.
(Assignee)

Comment 140

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #139)
> I still there are still some patches missing,
> like b2g/installer/package-manifest.in
> configure.in
> dom/moz.build
> 
> Please check what you did in WebNFC and add the missing patches back.

'Patch 5: (v5.1) Add build support for SE feature' has these files.
I haven't requested for review yet, as I had to check couple of things on my end still.  Will request for review on these files as well in next few days.
(Assignee)

Comment 141

3 years ago
Created attachment 8539849 [details] [diff] [review]
Part 2: (v2.2) Secure Element DOM Implementation
Attachment #8533057 - Attachment is obsolete: true
Attachment #8539849 - Flags: review?(allstars.chh)
(Assignee)

Comment 142

3 years ago
Created attachment 8539852 [details] [diff] [review]
Part 3: (v3.3) Secure Element Parent process Implementation. r=yoshi
Attachment #8536977 - Attachment is obsolete: true
Attachment #8539852 - Flags: review?(allstars.chh)
(Assignee)

Comment 143

3 years ago
Created attachment 8539856 [details] [diff] [review]
Part 4: (v4.1) Add moz.build for SecureElement files required for part 2 & 3 patches. r=yoshi
Attachment #8533068 - Attachment is obsolete: true
Attachment #8539856 - Flags: review?(allstars.chh)
(Assignee)

Comment 144

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #127)
> Comment on attachment 8533057 [details] [diff] [review]
> Patch 2: (v2.1) Secure Element DOM Implementation
> 
> Review of attachment 8533057 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: dom/secureelement/DOMSecureElement.js
> @@ +26,5 @@
> > +                                   "nsISyncMessageSender");
> > +
> > +XPCOMUtils.defineLazyServiceGetter(this, "iccProvider",
> > +                   "@mozilla.org/ril/content-helper;1",
> > +                   "nsIIccProvider");
> 
> Who uses this?
> 
Removed in the latest ver
> @@ +38,5 @@
> > +/*
> > + * Helper object that maintains sessionObj and its corresponding
> > + * channelObj for a given SE type
> > + */
> > +let SEStateHelper = {
> 
> this helper deserves another part of patch.
> 
I did not understand this. Are you suggesting this part of the code 'SEStateHelper' to be removed and upload another different patch ? (i;e; DOM patches will have two patches .) For now I still uploaded it as part of the same patch though.
> @@ +190,5 @@
> > +/**
> > + * ==============================================
> > + * SECommand
> > + * ==============================================
> > + */
> 
> I don't see any documentation in this comment.
> Same for below.
Added some docs
> 
> @@ +193,5 @@
> > + * ==============================================
> > + */
> > +function SECommand() {}
> > +SECommand.prototype = {
> > +  __init: function(cla, ins, p1, p2, data, le) {
> 
> function name
> 
> @@ +199,5 @@
> > +    this.ins = ins;
> > +    this.p1 = p1;
> > +    this.p2 = p2;
> > +    this.data = data;
> > +    this.le = le;
> 
> These members should also be defined in prototype.
> 
I have initialized all the members in the cstor. cstor does not take any arguments.
And in 'initialize' , initialize all the members appropriately! This is consistent across all other SExxx implementation in this file (and I guess with other DOM subsystems).
> @@ +215,5 @@
> > + */
> > +
> > +function SEResponse(aResponseInfo) {
> > +  this.sw1 = 0x00;
> > +  this.sw2 = 0x00;
> 
> these two lines are useless.
> 
Ok.
> @@ +218,5 @@
> > +  this.sw1 = 0x00;
> > +  this.sw2 = 0x00;
> > +  this.data = null;
> > +
> > +  this.channel = SEStateHelper.getChannelObjByToken(aResponseInfo.token);
> 
> data, and channel should be defined in prototype.
> 
Hopefully I have addressed this in the earlier comment.
> @@ +224,5 @@
> > +  if (!apduResponse.simResponse || apduResponse.simResponse.length === 0) {
> > +    if (DEBUG) debug('APDU Response: Empty / Not Set!');
> > +  } else {
> > +    this.data = apduResponse.simResponse.slice(0, apduResponse.length);
> > +  }
> 
> Why so complicated?
> aResponseInfo.response.simResponse?
> 
Ok . Agreed!
> @@ +248,5 @@
> > +  this._aid = aChannelInfo.aid;
> > +  this._channelToken = aChannelInfo.token;
> > +  this._sessionId = aChannelInfo.sessionId;
> > +  this.session = null;
> > +  this.openResponse = null;
> 
> define in prototype.
> 
> @@ +260,5 @@
> > +  classID: Components.ID("{181ebcf4-5164-4e28-99f2-877ec6fa83b9}"),
> > +  contractID: "@mozilla.org/secureelement/SEChannel;1",
> > +  QueryInterface: XPCOMUtils.generateQI([]),
> > +
> > +  initialize: function ic_initialize(win, openResponse) {
> 
> what's the ic_ in function name?
Fixed the function name to be consistent across the file now.
> And what is the difference between initialize and cstor?
> 
cstor will take no arguments now. In cstor function, all the required private + public members get initialized. 'initialize' initializes all the members with the appropriate vals.
> @@ +267,5 @@
> > +    // Update 'session' obj
> > +    this.session = SEStateHelper.getSessionObjById(this._sessionId);
> > +  },
> > +
> > +  transmit: function(command) {
> 
> function name
> 
> @@ +275,5 @@
> > +    if (typeof command.cla === 'undefined' ||
> > +        typeof command.ins === 'undefined' ||
> > +        typeof command.p1 === 'undefined' ||
> > +        typeof command.p2 === 'undefined' ||
> > +        !command)
> 
> I think the command is type of SECommand, right?
> Why can't these checks be done in SECommand cstor?
> 
Ok. It looks like we may not need to check these conditions as webidl will ensure this for DOM impl.
Since constructor of SECommand in webidl is as follows: - 
'Constructor(octet cla, octet ins, octet p1, octet p2 ....' If there are any values missing, webidl itself will throw exception while accessing 'SECommand'.
> @@ +276,5 @@
> > +        typeof command.ins === 'undefined' ||
> > +        typeof command.p1 === 'undefined' ||
> > +        typeof command.p2 === 'undefined' ||
> > +        !command)
> > +      return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> 
> nit, add {}.
> 
> {
> 
>   return Promise...
> };
> 
> @@ +280,5 @@
> > +      return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> > +                          "Invalid APDU, Missing Mandatory headers!");
> > +
> > +    let le = -1;
> > +    let dataLen = -1;
> 
> remove this line.
> 
Ok
> @@ +282,5 @@
> > +
> > +    let le = -1;
> > +    let dataLen = -1;
> > +    let offset = 0;
> > +    let apduFieldsLen = 4; // (CLA + INS + P1 + P2)
> 
> Can we merge 'offset' and apduFieldsLen' into one variable?
> 
I think after taking your other comment, we may not need these vars. It becomes little more straight-forward.
> @@ +283,5 @@
> > +    let le = -1;
> > +    let dataLen = -1;
> > +    let offset = 0;
> > +    let apduFieldsLen = 4; // (CLA + INS + P1 + P2)
> > +    dataLen = !command.data ? 0 : command.data.length;
> 
> more straightforward.
> 
> let dataLen = command.data ? command.data.length : 0;
> 
> @@ +292,5 @@
> > +      le = command.le;
> > +      apduFieldsLen++; // Le
> > +    }
> > +
> > +    if ((apduFieldsLen + dataLen) > SE.MAX_APDU_LEN)
> 
> nit, add {}
> 
Ok
> @@ +311,5 @@
> > +      }
> > +    }
> > +    if (le !== -1) {
> > +      apduCommand[offset] = command.le;
> > +    }
> 
> I think you should move these code to a helper that coverts SECommand to a
> TypedArray.
> 
I think after taking your other comment, we may not need these vars. It becomes little more straight-forward.
> @@ +321,5 @@
> > +                              apdu: apduCommand,
> > +                              channelToken: this._channelToken,
> > +                              aid: this._aid,
> > +                              sessionId: this._sessionId,
> > +                              appId: this._window.document.nodePrincipal.appId
> 
> Please explain why are these parameters for.
>
Ok 
> @@ +361,5 @@
> > +    return ['basic', 'logical'][type];
> > +  },
> > +
> > +  _checkClosed: function() {
> > +    if (this.isClosed === true) {
> 
> When will this.isClosed be set to true?
>
When the user attempts to close the channel by using closeAll (in Session) or close (in Channel)
> @@ +373,5 @@
> > + * SESession
> > + * ==============================================
> > + */
> > +
> > +function SESession(aSessionInfo) {
> 
> Please move these implementations by order.
> SEReader, SESesssion, SEChannel.
> 
Ok.
> @@ +392,5 @@
> > +
> > +  openBasicChannel: function(aid) {
> > +    // Not Supported for now!
> > +    return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> > +      "OpenBasicChannel() is not supported for SE type : " + SE.TYPE_UICC);
> 
> Should only reject when the type of READER is of UICC,
> not reject directly.
> Or if not supported for now, remove it.
> 
Removed it from now!
> @@ +401,5 @@
> > +    // According to SIMalliance_OpenMobileAPI v3 draft:
> > +    // In case of UICC it is recommended to reject the opening of the logical
> > +    // channel without a specific AID.
> > +    if (!aid || aid.length === 0) {
> > +      if (this.reader.type === SE.TYPE_UICC)
> 
> if (this.reader.type == UICC) should be moved to outter.
> 
Ok
> @@ +406,5 @@
> > +        return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> > +                                                  "AID is not specified!");
> > +    }
> > +
> > +    if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN)
> 
> nit, {}
Ok
> 
> @@ +407,5 @@
> > +                                                  "AID is not specified!");
> > +    }
> > +
> > +    if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN)
> > +      return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> 
> use double quotes.
> 
Ok
> @@ +410,5 @@
> > +    if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN)
> > +      return PromiseHelpers._rejectWithSEError('SEGenericError: ' +
> > +                                               "Invalid AID length - " + aid.length);
> > +
> > +    this._aid = Cu.waiveXrays(aid);
> 
> Why does we need waiveXrays here?
> 
Corrected this now. Now I just copy the aid to another private member.
> @@ +444,5 @@
> > +                                });
> > +  },
> > +
> > +  get atr() {
> > +    // 'Answer to Reset' is not supported for now, return null.
> 
> remove it.
Removed!
> Add this when you plan to implement it.
> 
Actually we need to have some discussion on how to retrieve 'atr value' from RIL stack. We may have to involve Qualcomm also here ? I will raise a CR to follow-up on this as well. 
> @@ +499,5 @@
> > +    });
> > +  },
> > +
> > +  get isSEPresent() {
> > +    return cpmm.sendSyncMessage("SE:CheckSEState",
> 
> Sync?
> 
Not needed now!
> @@ +527,5 @@
> > +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
> > +                                         Ci.nsISupportsWeakReference,
> > +                                         Ci.nsIObserver]),
> > +
> > +  init: function SEManagerInit(win) {
> 
> another style of function name.
> 
Corrected it now.
> @@ +530,5 @@
> > +
> > +  init: function SEManagerInit(win) {
> > +    this._window = win;
> > +    PromiseHelpers = new PromiseHelpersSubclass(this._window);
> > +    this.innerWindowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
> 
> What's this for?
> 
Removed
> @@ +539,5 @@
> > +    let perm = Services.perms.testExactPermissionFromPrincipal(principal,
> > +                                                               "secureelement-manage");
> > +    if (perm === Ci.nsIPermissionManager.ALLOW_ACTION) {
> > +      this._isAllowed = true;
> > +    }
> 
> I think WebIDL bindings could do this check for you.
> 
Yes, you are right
> @@ +543,5 @@
> > +    }
> > +
> > +    // Add the messages to be listened to.
> > +    const messages = ["SE:GetSEReadersResolved",
> > +                      "SE:OpenSessionResolved",
> 
> Why cannt we merge OpenSessionResolved and OpenSessionRejected into one
> message?
> 
Sorry, Couldn't understand this comment.
> @@ +567,5 @@
> > +     PromiseHelpers = null;
> > +     this._window = null;
> > +  },
> > +
> > +  _ensureAccess: function() {
> 
> Who calls this function?
> 
Removed
> @@ +592,5 @@
> > +  receiveMessage: function(aMessage) {
> > +    let data = aMessage.json;
> > +    let chromeObj = null;
> > +    let contentObj = null;
> > +    debug("receiveMessage(): " + aMessage.name + " " + JSON.stringify(data));
> 
> Don't use JSON.stringify.
> 
Ok. 
> @@ +601,5 @@
> > +    }
> > +
> > +    switch (aMessage.name) {
> > +      case "SE:GetSEReadersResolved":
> > +        let availableReaders = this._window.Array();
> 
> [];
Ok
(Assignee)

Comment 145

3 years ago
Created attachment 8539867 [details] [diff] [review]
Part 2: (v2.2) Secure Element DOM Implementation
Attachment #8539849 - Attachment is obsolete: true
Attachment #8539849 - Flags: review?(allstars.chh)
Attachment #8539867 - Flags: review?(allstars.chh)
(Assignee)

Comment 146

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #137)
> (In reply to Siddartha P from comment #133)
> > (In reply to Yoshi Huang[:allstars.chh] from comment #129)
> > As per open mobile spec, each application when registering shall be checked
> > against possible readerTypes (ex: 'uicc' (or) 'eSE') that it has permissions
> > to connect to. A certain wallet app can only have access to 'uicc'
> > readerType and not to 'eSE'. Though this kind of enforcement doesn't happen
> > in the existing patch, 
> Remove this and file another bug for this.
> Please don't add any code which won't be executed in this version.
> Or implement it.
> 
> And please file follow-up bugs you plan to fix and add them in the TODO in
> your patch.

Ok. We will soon raise bugs in next few and refer to them in code.
(Assignee)

Comment 147

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #138)
> Comment on attachment 8536977 [details] [diff] [review]
> Part 3: (v3.2) Secure Element Parent process Implementation. r=yoshi
> 
> Review of attachment 8536977 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> Why are these files in dom/system/gonk?
> Shouldn't these be located in dom/secureelement/gonk?
> 
Moved the files to 'dom/system/gonk'.

> Also I still didn't review the gMap part as I asked to indent it last time.
> But it's still the way it's.
I have now done this, hopefully to your liking!
> 
> ::: dom/system/gonk/SecureElement.js
> @@ +57,5 @@
> > +  "SE:GetChannelType",
> > +  "SE:IsChannelClosed"
> > +];
> > +
> > +const SE_CONTRACTID = "@mozilla.org/se;1";
> 
> use full name for se.
> 
Ok
> @@ +85,5 @@
> > +    classID: SE_CID,
> > +    contractID: SE_CONTRACTID,
> > +    classDescription: "SecureElement",
> > +    interfaces: []})
> > +};
> 
> What is this SecureElement for actually?
> 
In the recent patch, now 'SecureElement' is main object that combines with 'gSecureElementManager' (this is not a separate Lazygetter now).

> @@ +91,5 @@
> > +// Factory constructor
> > +function SEConnectorFactory() {}
> > +
> > +/**
> > + * Factory like pattern for getting the Connector obj.
> 
> What's a 'Connector' object?
Added few comments, and refer to this as 'SEConnector object' such as 'UiccConnector'

> and what's the difference between it and SecureElement?
'SEConnector object' such as 'UiccConnector' only deals with talking to 'iccProvider' and does operations / checks specific to the protocol. While 'SecureElement' (now 'SecureElementManager') deals with ipc message handling and bridges the functionality with 'gMap'. ('gMap' only deals with map management)
> 
> @@ +103,5 @@
> > +SEConnectorFactory.prototype = {
> > +
> > +  connectorClass: null,
> > +
> > +  get: function(options) {
> 
> get what? 
> 
Renamed to 'getConnector'

> for the argument, use 'type' directly.
>
Ok 
> @@ +109,5 @@
> > +      case SE.TYPE_ESE:
> > +        if (DEBUG) debug('UnSupported SEConnector : ' + SE.TYPE_ESE);
> > +        break;
> > +      case SE.TYPE_UICC:
> > +      default: // Default ConnectorClass is UiccConnector
> 
> Why Uicc is default?
> 
Addressed this now!
> @@ +113,5 @@
> > +      default: // Default ConnectorClass is UiccConnector
> > +        this.connectorClass = UiccConnector;
> > +        break;
> > +    }
> > +    return this.connectorClass;
> 
> connectorClass seems useless.
> 
Ok.
> switch (type) {
>   case ESE:
>     return null;
>   case UICC:
>     return UiccConnector;
> }
> 
> @@ +190,5 @@
> > +                 ...
> > +                 ...
> > +                 ...
> > +       ]
> > +    } */
> 
> indent this, or I won't be able to review this.
> 
Yep, I did it now!
> @@ +439,5 @@
> > +    isChannelClosed: function(data) {
> > +      return !this.appInfoMap[data.appId].sessions[data.sessionId].channels[data.channelToken];
> > +    },
> > +
> > +
> 
> extra line.
> 
Ok
> @@ +464,5 @@
> > +     * Private internal functions
> > +     */
> > +
> > +    // Retrieves all the channels for the given 'channels' object
> > +    _getChannels: function(channels) {
> 
> Make it more easier to understand.
> 
Added few comments with an example.
> @@ +468,5 @@
> > +    _getChannels: function(channels) {
> > +      if (!channels)
> > +        return null;
> > +
> > +      let channelNumbers = new Array();
> 
> []
> 
Ok
> @@ +526,5 @@
> > +XPCOMUtils.defineLazyGetter(this, "UiccConnector", function() {
> > +  return {
> > +    QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccListener]),
> > +
> > +    _isUiccSecureElementPresent: false,
> 
> using shorter name
> 
Ok
> @@ +545,5 @@
> > +    notifyIccInfoChanged: function() {},
> > +
> > +    // This function acts as a trigger to listen on 'nsIIccListener' callbacks
> > +    start: function() {
> > +      if (DEBUG) debug("Default Client ID " + PREFERRED_UICC_CLIENTID);
> 
> remove this line.
> 
Ok
> @@ +566,5 @@
> > +    doOpenChannel: function(aid, callback) {
> > +      if (!aid || aid.length === 0) {
> > +        // According to SIMalliance_OpenMobileAPI v3 draft,
> > +        // it is recommended not to support it.
> > +        debug('AID is not set. Reject the openChannel request!');
> 
> use double quote.
> 
Ok
> @@ +570,5 @@
> > +        debug('AID is not set. Reject the openChannel request!');
> > +        throw new Error(SE.ERROR_SECURITY);
> > +      }
> > +
> > +      if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {
> 
> let aidLen = aid ? aid.length : 0;
> 
> then you can merge these two if checks.
> 
Ok
> Also I think this check should be done in DOM part.
> 
Actually, DOM part has its side of checks in place. Since this is in parent process, maybe it is still better to be conservative (for security reasons perhaps) and perform the checks anyways since these IPC commands are coming from content.
> @@ +602,5 @@
> > +    doTransmit: function(command, callback) {
> > +      let cla = command.cla & 0xFF;
> > +      let ins = command.ins & 0xFF;
> > +      let p1 = command.p1 & 0xFF;
> > +      let p2 = command.p2 & 0xFF;
> 
> Is these & 0xff neccesary?
> If you have defined your WebIDL well, these should be done already.
> 
Actually you are right. Maybe again for being conservative and making SecureElement parent process do its needed checks and perhaps not relying on DOM to do the checks only. Because after this, the stack directly talks to low level APIs.
> @@ +619,5 @@
> > +      }
> > +      else if (command.le !== -1) {
> > +        // Only le is set. 'p3=le'. Response expected!
> > +        p3 = command.le;
> > +      }
> 
> let p3 = command.data ?
>            commmand.data.length : 
>            (command.le != -1 ? command.le : 0x00);
> let appendLe = (command.data != null) && (command.le != -1);
> 
Ok
> @@ +622,5 @@
> > +        p3 = command.le;
> > +      }
> > +
> > +      // At this point perform more sanity checks on the c-apdu
> > +      if (p3 + SE.APDU_HEADER_LEN > SE.MAX_APDU_LEN) {
> 
> Do this in Content?
> 
Also , did this in content.
> @@ +635,5 @@
> > +          typeof command.p1 === 'undefined' ||
> > +          typeof command.p2 === 'undefined') {
> > +        debug('Mandatory command headers Missing! - Invalid Command');
> > +        throw new Error(SE.ERROR_IO);
> > +      }
> 
> Shouldn't this be done in Content side?
> 
Actually, based on your earlier comment, I removed this completely.
> @@ +651,5 @@
> > +        }
> > +        if (DEBUG) debug("Attempting to transmit an ISO command");
> > +      } else {
> > +        if (DEBUG) debug("Attempting to transmit GlobalPlatform command");
> > +      }
> 
> done in content ?
> 
> @@ +674,5 @@
> > +        let leHexStr = SE.gUtils.byteTohexString(le & 0xFF) +
> > +                       SE.gUtils.byteTohexString((le >> 8) & 0xFF) ;
> > +        data += leHexStr;
> > +      }
> > +      let channel = this._getChannelNumber(cla & 0xFF);
> 
> you already & 0xff in the beginning of this function.
> 
Removed this though.
> @@ +702,5 @@
> > +      // TBD: Finally Perform checks with ACE module
> > +
> > +      let count = 0;
> > +      for (let index = 0; index < channels.length; index++) {
> > +        let channelNumber = channels[index];
> 
> Can't we just call it 'channel'? Why 'channelNumber' ?
> 
Renamed across the file, to just 'channel'
> @@ +703,5 @@
> > +
> > +      let count = 0;
> > +      for (let index = 0; index < channels.length; index++) {
> > +        let channelNumber = channels[index];
> > +        if (channelNumber === SE.TYPE_BASIC_CHANNEL) {
> 
> This looks totally confusing.
> if this is a type, then it should be named 'channelType'. Also same for the
> channels.
> 
My bad! Typo on my side. This should be 'BASIC_CHANNEL' only . Added this new constant in se_consts.js file, and removed TYPE_XXX_CHANNEL constants as these can be boolean (again based on one your earlier coments)
> @@ +847,5 @@
> > +        "personalizationInProgress",
> > +        "permanentBlocked"
> > +      ];
> > +      let cardState = iccProvider.getCardState(PREFERRED_UICC_CLIENTID);
> > +      return (((cardState !== null) && (notReadyStates.indexOf(cardState) == -1)) ? true : false);
> 
> can't we just compare cardState to CARD_STATE_READY?
> 
Maybe. One of my testing SIMs is in 'pukblocked' state. As per the protocol, SE stack should still be able to talk to uicc SE normally. There are (as you may know) multiple such OK states other than just 'card ready' where SE operations should be permitted. Hence picked up the card states that are not suitable for SE operations and have the checks against such 'not ready states'. (as per spec)
> @@ +861,5 @@
> > + * It mainly interacts with 'gMap' to query the state of Readers, Sessions, Channels,
> > + * while it interacts with 'Connector instances' to perform low level SE-related
> > + * (open,close,transmit) I/O operations.
> > + */
> > +XPCOMUtils.defineLazyGetter(this, "gSecureElementManager", function() {
> 
> I don't think this should be a lazy getter.
> 
Ok. Agreed
> @@ +876,5 @@
> > +      Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
> > +      this._registerMessageListeners();
> > +      // This is needed for UiccConnector to start listening on uicc state changes
> > +      UiccConnector.start();
> > +      this.connectorFactory = new SEConnectorFactory();
> 
> Given that you have ConnectorFactory, you should access UiccConnector
> through that factory.
> Otherwise your 'factory' will be useless.
> 
Ok. Addressed this.
> @@ +1070,5 @@
> > +     */
> > +
> > +    receiveMessage: function(msg) {
> > +      if (DEBUG) debug("Received '" + msg.name + "' message from content process" + ": " +
> > +                       JSON.stringify(msg.json));
> 
> use msg.data
> 
Ok
> @@ +1075,5 @@
> > +      let status = SE.ERROR_GENERIC;
> > +      let message = msg;
> > +      let promiseStatus = "Rejected";
> > +      let options = { status: status,
> > +                                 resolverId: msg.json ? msg.json.resolverId : null };
> 
> align.
> 
Ok
> @@ +1184,5 @@
> > +          return gMap.isSessionClosed(msg.json);
> > +        case "SE:GetChannelType":
> > +          return gMap.getChannelType(msg.json);
> > +        case "SE:IsChannelClosed":
> > +          return gMap.isChannelClosed(msg.json);
> 
> That should be some notifications back to the DOM part, like
> notifySEPresent, notifSessionClosed, notifyChannelClosed, ... etc,
> so these getters could be done in DOM layer.
> 
Ok. Added 'notifySEPresent' in this patch. 
In my opinion, 'notifSessionClosed', 'notifyChannelClosed' may not be needed as the same purpose is served by 'closeAllChannelsBySessionResolved' & 'closeChannelResolved' IPC events. Also 'close operation' on say a 'session' / 'channel' or on 'array of channels' is pretty much a top-down operation. i;e; Gaia apps issue these commands in the form of 'closeAll (in SESession instance)' or 'close (in SEChannel instance)' or 'closeAll (in SEReader instance)'. SE stack (mainly SecureElement.js) in any case wouldn't know if the underlying opened channels get closed as there is no 'unsolicited event from RIL notifying it'. Hence the current solution. Hopefully you are ok with this approach
> @@ +1187,5 @@
> > +        case "SE:IsChannelClosed":
> > +          return gMap.isChannelClosed(msg.json);
> > +        default:
> > +          throw new Error("Don't know about this message: " + msg.name);
> > +          return;
> 
> You already did this check in line 1095
> 
Ok. Got it.
> @@ +1189,5 @@
> > +        default:
> > +          throw new Error("Don't know about this message: " + msg.name);
> > +          return;
> > +      }
> > +      msg.target.sendAsyncMessage(msg.name + promiseStatus, options);
> 
> move this line into cases, like GetSEReaders, OpenSession.
> 
Ok. Infact in the latest patch, refactored the entire SE IPC commands into one handler 'handleDOMRequests'. This should take care of most of SE IPC commands handling.
> @@ +1206,5 @@
> > +    }
> > +  };
> > +});
> > +
> > +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SecureElement]);
> 
> Seems to me you should put SecureElementManager here.
>
Ok 
> ::: dom/system/gonk/moz.build
> @@ +100,5 @@
> > +    'SecureElement.js',
> > +    'SecureElement.manifest',
> > +]
> > +EXTRA_JS_MODULES += [
> > +        'se_consts.js',
> 
> indent.
> 
Ok
> Also this should be moved to somewhere like dom/secureelement/gonk
> 
Ok
> ::: dom/system/gonk/se_consts.js
> @@ +15,5 @@
> > +
> > +/* Copyright © 2014, Deutsche Telekom, Inc. */
> > +
> > +// Set to true to debug SecureElement (SE) stack
> > +this.DEBUG_ALL = true;
> 
> default to false.
> 
Ok
> @@ +18,5 @@
> > +// Set to true to debug SecureElement (SE) stack
> > +this.DEBUG_ALL = true;
> > +
> > +// Set individually to debug specific layers
> > +this.DEBUG_ACE = false || DEBUG_ALL;
> 
> ?
> remove this.
> 
Ok
> @@ +19,5 @@
> > +this.DEBUG_ALL = true;
> > +
> > +// Set individually to debug specific layers
> > +this.DEBUG_ACE = false || DEBUG_ALL;
> > +this.DEBUG_SE = false || DEBUG_ALL;
> 
> reverse the order.
> 
Ok
> DEBUG_ALL || false;
> 
> @@ +24,5 @@
> > +
> > +// Ideally this should have been 3, as we do not allow basic channel' : 0 on 'uicc'.
> > +// Max number of supplementary logical channels available would be : [1, 2, or 3].
> > +// Other SE types may support upto max 4.
> > +
> 
> extra line.
>
Ok 
> @@ +29,5 @@
> > +// Maximun logical channels per session.
> > +this.MAX_CHANNELS_ALLOWED_PER_SESSION = 4;
> > +
> > +this.TYPE_BASIC_CHANNEL = 0;
> > +this.TYPE_LOGICAL_CHANNEL = 1;
> 
> Seems boolean is enough.
> 
ok
> @@ +61,5 @@
> > +this.ERROR_IO                 = 'SEIoError';
> > +this.ERROR_BADSTATE           = 'SEBadStateError';
> > +this.ERROR_INVALIDCHANNEL     = 'SEInvalidChannelError';
> > +this.ERROR_INVALIDAPPLICATION = 'SEInvalidApplicationError';
> > +this.ERROR_GENERIC            = 'SEGenericError';
> 
> double quotes.
> 
ok
> @@ +64,5 @@
> > +this.ERROR_INVALIDAPPLICATION = 'SEInvalidApplicationError';
> > +this.ERROR_GENERIC            = 'SEGenericError';
> > +
> > +this.TYPE_UICC = 'uicc';
> > +this.TYPE_ESE = 'eSE';
> 
> ditto.
> 
ok
> @@ +66,5 @@
> > +
> > +this.TYPE_UICC = 'uicc';
> > +this.TYPE_ESE = 'eSE';
> > +
> > +this.gUtils = {
> 
> move this to a JSM, and these functions should have tests.
> 
Valid point. In our team we had a consensus, and Krzysztof is going to upload the lib very soon for your review in this bug itself. As you have already noted, this lib will then be used by both SE stack and ACE modules. Therefore I have not made any modifications for this for now. Please do review other parts. Thanks!
> @@ +67,5 @@
> > +this.TYPE_UICC = 'uicc';
> > +this.TYPE_ESE = 'eSE';
> > +
> > +this.gUtils = {
> > +  hexStringToBytes: function(hexString) {
> 
> hexStringToByteArray
> 
> @@ +69,5 @@
> > +
> > +this.gUtils = {
> > +  hexStringToBytes: function(hexString) {
> > +    let bytes = [];
> > +    let length = hexString.length;
> 
> what if hexString is null or undefined?
> 
> @@ +78,5 @@
> > +
> > +    return bytes;
> > +  },
> > +
> > +  byteTohexString: function(array) {
> 
> byteArrayToHexString
> and using the same naming, 'array' or 'bytes'.
> 
> @@ +80,5 @@
> > +  },
> > +
> > +  byteTohexString: function(array) {
> > +    let hexString = "";
> > +    let hex;
> 
> move hex into for loop.
> 
> @@ +83,5 @@
> > +    let hexString = "";
> > +    let hex;
> > +
> > +    if (!array || array.length === 0)
> > +      return hexString;
> 
> let length = array ? array.length : 0;
> 
> for (let i = 0; i < length; i++)
> 
> then the if check can be removed now.
> 
> @@ +86,5 @@
> > +    if (!array || array.length === 0)
> > +      return hexString;
> > +
> > +    for (let i = 0; i < array.length; i++) {
> > +      hex = array[i].toString(16).toUpperCase();
> 
> If you want upperCase, do it in the return.
> 
> return hexString.toUpperCase();
(Assignee)

Comment 148

3 years ago
Created attachment 8539927 [details] [diff] [review]
Part 3: (v3.3) Secure Element Parent process Implementation. r=yoshi

Obsoleting the just attached Part 3 (v3.3) patch and attaching a new one. The difference being in 'receiveMessage:' function. Removed all the local variables which are not being used.
Attachment #8539852 - Attachment is obsolete: true
Attachment #8539852 - Flags: review?(allstars.chh)
Attachment #8539927 - Flags: review?(allstars.chh)
Created attachment 8540295 [details] [diff] [review]
Part 6: (v1) SEUtils.jsm, r=allstars.chh

This is SEUtils.jsm with utility functions which will be used by Secure Element API and ACE.

Right now we don't run this code in emulator so it's hard to run xpcshell tests for it. Do you want me to also add xpcshell test for it in this bug or should this be raised as a followup once this will be landed?
Attachment #8540295 - Flags: review?(allstars.chh)
Comment on attachment 8539867 [details] [diff] [review]
Part 2: (v2.2) Secure Element DOM Implementation

Review of attachment 8539867 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/secureelement/DOMSecureElement.js
@@ +41,5 @@
> +
> +  /*
> +    // Structure of '_stateInfoMap'.
> +
> +    // 'sessionIds' and 'channelTokens' are uuids generated in parent process.

I think both are generated from UUID, right?
so either call them {sessionToken, channelToken} or {sessionId, channelId}.
make the naming consistent.

@@ +72,5 @@
> +   */
> +  _stateInfoMap: {},
> +
> +  addReaderObjs(readerObjs) {
> +    for (let index = 0; index < readerObjs.length; readerObjs++) {

readerObjs++?

@@ +73,5 @@
> +  _stateInfoMap: {},
> +
> +  addReaderObjs(readerObjs) {
> +    for (let index = 0; index < readerObjs.length; readerObjs++) {
> +      let aReaderObj = readerObjs[index];

why prefix with a?

@@ +83,5 @@
> +    }
> +  },
> +
> +  getReaderObjByType(type) {
> +    let map = this._stateInfoMap[type];

map ? you called it sessionObj in line 82.

@@ +90,5 @@
> +
> +  deleteReaderObjByType(type) {
> +    let sessions = this._stateInfoMap[type].sessions;
> +    Object.keys(sessions).forEach((sessionId) => {
> +      if (sessions[sessionId]) {

is this 'if' check neccesary?

@@ +96,5 @@
> +      }
> +    });
> +  },
> +
> +  addSessionObj(sessionObj, aSessionInfo) {

either make it all prefix with a, or not at all.

@@ +97,5 @@
> +    });
> +  },
> +
> +  addSessionObj(sessionObj, aSessionInfo) {
> +    this._stateInfoMap[aSessionInfo.type].sessions[aSessionInfo.sessionId] = {

TODO

@@ +106,5 @@
> +
> +  getSessionObjById(sessionId) {
> +    let keys = Object.keys(this._stateInfoMap);
> +    for (let i = 0; i < keys.length; i++) {
> +      let aKey = keys[i];

let key = ...

@@ +165,5 @@
> +  }
> +};
> +
> +function PromiseHelpersSubclass(win) {
> +   this._window = win;

indent two spaces.

@@ +173,5 @@
> +  __proto__: DOMRequestIpcHelper.prototype,
> +
> +  _window: null,
> +
> +  _createSEPromise: function(aCallback) {

Please use the same syntax for object method.
Also why prefix with _?

This is called by other objects.

@@ +183,5 @@
> +      aCallback(resolverId);
> +    });
> +  },
> +
> +

extra line

@@ +184,5 @@
> +    });
> +  },
> +
> +
> +  _rejectWithSEError: function(aReason) {

ditto, remove _

@@ +212,5 @@
> +  classID: Components.ID("{1c7bdba3-cd35-4f8b-a546-55b3232457d5}"),
> +  contractID: "@mozilla.org/secureelement/SEReader;1",
> +  QueryInterface: XPCOMUtils.generateQI([]),
> +
> +  initialize: function initialize(win) {

now you add function name?
Use consistent style.

@@ +217,5 @@
> +    this._window = win;
> +    this._isSEPresent = true;
> +  },
> +
> +  openSession: function openSession() {

Shouldn't this check this._isSEPresent first?

@@ +218,5 @@
> +    this._isSEPresent = true;
> +  },
> +
> +  openSession: function openSession() {
> +    return PromiseHelpers._createSEPromise((aResolverId) => {

I think you could just update your promiseHelper a bit, 
you could take 'reader' object when you new your promise, when the promise resolves you can get the 'reader' back.
So no need to StateHelper.

Same idea for object below.

@@ +257,5 @@
> +  },
> +
> +  set isSEPresent(isSEPresent) {
> +    this._isSEPresent = isSEPresent;
> +  }

Wouldn't it be easier if you just define isSEPresent?

@@ +258,5 @@
> +
> +  set isSEPresent(isSEPresent) {
> +    this._isSEPresent = isSEPresent;
> +  }
> +};

Where is 'type' attribute?

@@ +268,5 @@
> + * hosted by the Secure Element.
> + */
> +function SESession() {
> +  this._sessionId = null;
> +  this.reader = null;

move this to prototype.

@@ +278,5 @@
> +  classID: Components.ID("{2b1809f8-17bd-4947-abd7-bdef1498561c}"),
> +  contractID: "@mozilla.org/secureelement/SESession;1",
> +  QueryInterface: XPCOMUtils.generateQI([]),
> +
> +  initialize: function initialize(win, result, data) {

pass sessionId and type directly.

@@ +292,5 @@
> +    // According to SIMalliance_OpenMobileAPI v4 spec,
> +    // in case of UICC it is recommended to reject the opening of the logical
> +    // channel without a specific AID.
> +    if (this.reader.type === SE.TYPE_UICC) {
> +      if (!aid || aid.length === 0) {

This check is totally not neccesary because you already check AID in line 302.

@@ +300,5 @@
> +    }
> +
> +    if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {
> +      return PromiseHelpers._rejectWithSEError(SE.ERROR_GENERIC +
> +            " Invalid AID length - " + aid.length);

The error message doesn't fully match WebIDL.

@@ +304,5 @@
> +            " Invalid AID length - " + aid.length);
> +    }
> +
> +    // copy the aid
> +    this._aid = aid.subarray(0);

define this in prototype.

@@ +356,5 @@
> +    if (this.isClosed) {
> +      throw new Error(SE.ERROR_BADSTATE + " Session Already Closed!");
> +    }
> +  }
> +};

remove atr/openBasicChannel from WebIDL.

@@ +362,5 @@
> +/**
> + * Instance of 'SECommand' dom object represent C-APDU to be sent to a
> + * secure element.
> + */
> +function SECommand() {

nit, move SECommand after SEChannel

@@ +368,5 @@
> +  this.ins = 0x00;
> +  this.p1 = 0xFF;
> +  this.p2 = 0xFF;
> +  this.data = null;
> +  this.le = -1;

move these to prototype.

@@ +372,5 @@
> +  this.le = -1;
> +}
> +
> +SECommand.prototype = {
> +  __init: function __init(cla, ins, p1, p2, data, le) {

check format.

@@ +394,5 @@
> + */
> +function SEChannel() {
> +  this._aid = null;
> +  this._channelToken = null;
> +  this._sessionId = null;

consistent naming for Token or id.

@@ +395,5 @@
> +function SEChannel() {
> +  this._aid = null;
> +  this._channelToken = null;
> +  this._sessionId = null;
> +  this._channelType = "logical";

Why logical is default?

@@ +397,5 @@
> +  this._channelToken = null;
> +  this._sessionId = null;
> +  this._channelType = "logical";
> +  this.session = null;
> +  this.openResponse = null;

move these to prototype.

@@ +409,5 @@
> +  classID: Components.ID("{181ebcf4-5164-4e28-99f2-877ec6fa83b9}"),
> +  contractID: "@mozilla.org/secureelement/SEChannel;1",
> +  QueryInterface: XPCOMUtils.generateQI([]),
> +
> +  initialize: function initialize(win, result, data) {

pass aid, sessionId directly.

@@ +417,5 @@
> +    this._channelType = result.isBasicChannel ? "basic" : "logical";
> +    // Update the 'channel token' that identifies and represents this
> +    // instance of the object
> +    this._channelToken = result.channelToken;
> +    this.openResponse = Cu.cloneInto(new Uint8Array(result.openResponse), win);

Why cloneInto?

@@ +425,5 @@
> +
> +  transmit: function transmit(command) {
> +    this._checkClosed();
> +
> +    let dataLen = (!command.data) ? 0 : command.data.length;

check if command is null/undefined first.
and let dataLen = command.data ? command.data.length : 0;

@@ +437,5 @@
> +      cla: command.cla,
> +      ins: command.ins,
> +      p1: command.p1,
> +      p2: command.p2,
> +      data: (!command.data) ? null : command.data,

data: command.data || null

@@ +510,5 @@
> +    if (this.isClosed) {
> +      throw new Error(SE.ERROR_BADSTATE +" Channel Already Closed!");
> +    }
> +  }
> +};

Where is session defined?

@@ +520,5 @@
> +function SEResponse() {
> +  this.sw1 = 0x00;
> +  this.sw2 = 0x00;
> +  this.data = null;
> +  this.channel = null;

move these to prototype.

@@ +529,5 @@
> +  contractID: "@mozilla.org/secureelement/SEResponse;1",
> +  QueryInterface: XPCOMUtils.generateQI([]),
> +
> +  initialize: function initialize(result, data) {
> +    this.data = result.simResponse ?

the response should be conforming to ISO 7816-4, so 'sim' prefix should be removed.

@@ +551,5 @@
> +
> +  _window: null,
> +
> +  classID: Components.ID("{4a8b6ec0-4674-11e4-916c-0800200c9a66}"),
> +  contractID: "@mozilla.org/navigatorSEManager;1",

@mozilla.org/secureelement/SEManager;1

@@ +554,5 @@
> +  classID: Components.ID("{4a8b6ec0-4674-11e4-916c-0800200c9a66}"),
> +  contractID: "@mozilla.org/navigatorSEManager;1",
> +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
> +                                         Ci.nsISupportsWeakReference,
> +                                         Ci.nsIObserver]),

where did you implement nsIObserver?

@@ +580,5 @@
> +
> +    this.initDOMRequestHelper(win, messages);
> +  },
> +
> +  uninit: function uninit() {

who calls this?

@@ +604,5 @@
> +  },
> +
> +  receiveMessage: function(aMessage) {
> +    let result = aMessage.json.result;
> +    let data = aMessage.json.metadata;

aMessage.data

@@ +619,5 @@
> +    }
> +
> +    switch (aMessage.name) {
> +      case "SE:GetSEReadersResolved":
> +        let availableReaders = [];

why not just call it 'readers'?

@@ +621,5 @@
> +    switch (aMessage.name) {
> +      case "SE:GetSEReadersResolved":
> +        let availableReaders = [];
> +        for (let i = 0; i < result.readers.length; i++) {
> +          chromeObj = new SEReader(result.readers[i]);

What's this? you forgot .type ?
It doesn't match line 205.

@@ +680,5 @@
> +      case "SE:CloseChannelRejected":
> +      case "SE:TransmitAPDURejected":
> +      case "SE:CloseAllByReaderRejected":
> +      case "SE:CloseAllBySessionRejected":
> +        let error = data.error ? data.error : SE.ERROR_GENERIC;

data.error || SE.ERROR_GENERIC

@@ +683,5 @@
> +      case "SE:CloseAllBySessionRejected":
> +        let error = data.error ? data.error : SE.ERROR_GENERIC;
> +        resolver.reject(error);
> +        break;
> +      case "SE:NotifySEPresent":

check permission.
Attachment #8539867 - Flags: review?(allstars.chh) → review-
Comment on attachment 8539927 [details] [diff] [review]
Part 3: (v3.3) Secure Element Parent process Implementation. r=yoshi

Review of attachment 8539927 [details] [diff] [review]:
-----------------------------------------------------------------

As required by ACE, you need to have a nsISecureElement here.

canceling r? for IDL is missing is this patch, and my previous comments are not addressed yet.

::: dom/secureelement/gonk/SecureElement.js
@@ +598,5 @@
> +      });
> +    },
> +
> +    doTransmit: function(command, callback) {
> +      let cla = command.cla & 0xFF;

if you'd still like to check the types in parent process, please add another IDL for this.

@@ +1120,5 @@
> +
> +  handleOpenSession: function(msg) {
> +    let promiseStatus = "Rejected";
> +    let options = {
> +      metadata: msg.json

use msg.data, as I said before.

::: dom/secureelement/gonk/se_consts.js
@@ +67,5 @@
> +
> +this.TYPE_UICC = "uicc";
> +this.TYPE_ESE = "eSE";
> +
> +this.gUtils = {

remove this before sending r?
Attachment #8539927 - Flags: review?(allstars.chh)
Comment on attachment 8540295 [details] [diff] [review]
Part 6: (v1) SEUtils.jsm, r=allstars.chh

Review of attachment 8540295 [details] [diff] [review]:
-----------------------------------------------------------------

where is moz.build ?
r- for this.

And JSM needs unit test like xpcshell.

::: dom/secureelement/SEUtils.jsm
@@ +21,5 @@
> +  },
> +
> +  hexStringToByteArray: function hexStringToByteArray(hexStr) {
> +    let array = [];
> +

check string length is % 2 == 0;

@@ +23,5 @@
> +  hexStringToByteArray: function hexStringToByteArray(hexStr) {
> +    let array = [];
> +
> +    let len = hexStr ? hexStr.length : 0;
> +    for (let i = 0; i < len; i+=2) {

nit, space before and after '+='

@@ +48,5 @@
> +
> +    return true;
> +  },
> +
> +  ensureIsArray: function ensureIsArray(obj) {

What's this function for?

@@ +69,5 @@
> +     */
> +    parse: function parse(tlv) {
> +      if (typeof tlv === "string") {
> +        tlv = SEUtils.hexStringToBytes(tlv);
> +      }

this looks strange, what do you expect the type of tlv?
Attachment #8540295 - Flags: review?(allstars.chh) → review-
Comment on attachment 8540295 [details] [diff] [review]
Part 6: (v1) SEUtils.jsm, r=allstars.chh

Review of attachment 8540295 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/secureelement/SEUtils.jsm
@@ +59,5 @@
> +   * @todo investigate if full TLV parser needed
> +   */
> +  simpleTLV: {
> +    // PKCS#15 container tags
> +    CONTAINER_TAGS: [0x30, 0x62, 0xA0, 0xA1, 0xA5, 0xA7],

Where does this come from?
const these.
Comment on attachment 8539856 [details] [diff] [review]
Part 4: (v4.1) Add moz.build for SecureElement files required for part 2 & 3 patches. r=yoshi

Review of attachment 8539856 [details] [diff] [review]:
-----------------------------------------------------------------

dom/webid/moz.build is still missing.

::: dom/secureelement/moz.build
@@ +7,5 @@
> +
> +if CONFIG['MOZ_SECUREELEMENT']:
> +    EXTRA_COMPONENTS += [
> +      'DOMSecureElement.js',
> +      'DOMSecureElement.manifest',

indent
Attachment #8539856 - Flags: review?(allstars.chh) → review-
Comment on attachment 8539867 [details] [diff] [review]
Part 2: (v2.2) Secure Element DOM Implementation

Review of attachment 8539867 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/secureelement/DOMSecureElement.js
@@ +417,5 @@
> +    this._channelType = result.isBasicChannel ? "basic" : "logical";
> +    // Update the 'channel token' that identifies and represents this
> +    // instance of the object
> +    this._channelToken = result.channelToken;
> +    this.openResponse = Cu.cloneInto(new Uint8Array(result.openResponse), win);

Or if openResponse is type of Uint8Array, you shouldn't need the 'new' op.
Created attachment 8541241 [details] [diff] [review]
Part 6: (v1.1) SEUtils.jsm, r=allstars.chh

Addressed all the issues from comment 152. 

|simpleTLV.parse| and |ensureIsArray| were removed in this version of patch. I've discussed this with Kamil and we agreed that these are methods specific for GPAccessRulesManager, so they will be part of ACE patch.

Unit test were checked on latest Gecko and.
Attachment #8540295 - Attachment is obsolete: true
Attachment #8541241 - Flags: review?(allstars.chh)
Comment on attachment 8541241 [details] [diff] [review]
Part 6: (v1.1) SEUtils.jsm, r=allstars.chh

Review of attachment 8541241 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/secureelement/tests/unit/test_SEUtils.js
@@ +8,5 @@
> +
> +Components.utils.import("resource://gre/modules/SEUtils.jsm");
> +
> +const VALID_HEX_STR = "0123456789ABCDEF";
> +const VALID_HEX_STR_LC = "0123456789abcdef";

VALID_HEX_STR.toLowerCase() is enough.

@@ +18,5 @@
> +}
> +
> +add_test(function test_byteArrayToHexString() {
> +  let hexStr = SEUtils.byteArrayToHexString(VALID_BYTE_ARR);
> +  ok(hexStr === VALID_HEX_STR, 

trailing ws
Attachment #8541241 - Flags: review?(allstars.chh) → review+
(Assignee)

Comment 158

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #150)
> Comment on attachment 8539867 [details] [diff] [review]
> Part 2: (v2.2) Secure Element DOM Implementation
> 
> Review of attachment 8539867 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: dom/secureelement/DOMSecureElement.js
> @@ +41,5 @@
> > +
> > +  /*
> > +    // Structure of '_stateInfoMap'.
> > +
> > +    // 'sessionIds' and 'channelTokens' are uuids generated in parent process.
> 
> I think both are generated from UUID, right?
> so either call them {sessionToken, channelToken} or {sessionId, channelId}.
> make the naming consistent.
> 
Ok.
> @@ +72,5 @@
> > +   */
> > +  _stateInfoMap: {},
> > +
> > +  addReaderObjs(readerObjs) {
> > +    for (let index = 0; index < readerObjs.length; readerObjs++) {
> 
> readerObjs++?
> 
This was a mistake / typo. Fixed it in the latest patch
> @@ +73,5 @@
> > +  _stateInfoMap: {},
> > +
> > +  addReaderObjs(readerObjs) {
> > +    for (let index = 0; index < readerObjs.length; readerObjs++) {
> > +      let aReaderObj = readerObjs[index];
> 
> why prefix with a?
> 
Ok. Removed prefix 'a' now. 
> @@ +83,5 @@
> > +    }
> > +  },
> > +
> > +  getReaderObjByType(type) {
> > +    let map = this._stateInfoMap[type];
> 
> map ? you called it sessionObj in line 82.
Yes, fixed this as well.
> 
> @@ +90,5 @@
> > +
> > +  deleteReaderObjByType(type) {
> > +    let sessions = this._stateInfoMap[type].sessions;
> > +    Object.keys(sessions).forEach((sessionId) => {
> > +      if (sessions[sessionId]) {
> 
> is this 'if' check neccesary?
Not needed. Removed it.
> 
> @@ +96,5 @@
> > +      }
> > +    });
> > +  },
> > +
> > +  addSessionObj(sessionObj, aSessionInfo) {
> 
> either make it all prefix with a, or not at all.
> 
Removed prefix a
> @@ +97,5 @@
> > +    });
> > +  },
> > +
> > +  addSessionObj(sessionObj, aSessionInfo) {
> > +    this._stateInfoMap[aSessionInfo.type].sessions[aSessionInfo.sessionId] = {
> 
> TODO
> 
> @@ +106,5 @@
> > +
> > +  getSessionObjById(sessionId) {
> > +    let keys = Object.keys(this._stateInfoMap);
> > +    for (let i = 0; i < keys.length; i++) {
> > +      let aKey = keys[i];
> 
> let key = ...
> 
ok
> @@ +165,5 @@
> > +  }
> > +};
> > +
> > +function PromiseHelpersSubclass(win) {
> > +   this._window = win;
> 
> indent two spaces.
> 
Ok
> @@ +173,5 @@
> > +  __proto__: DOMRequestIpcHelper.prototype,
> > +
> > +  _window: null,
> > +
> > +  _createSEPromise: function(aCallback) {
> 
> Please use the same syntax for object method.
> Also why prefix with _?
> 
ok
> This is called by other objects.
> 
> @@ +183,5 @@
> > +      aCallback(resolverId);
> > +    });
> > +  },
> > +
> > +
> 
> extra line
> 
ok
> @@ +184,5 @@
> > +    });
> > +  },
> > +
> > +
> > +  _rejectWithSEError: function(aReason) {
> 
> ditto, remove _
> 
ok
> @@ +212,5 @@
> > +  classID: Components.ID("{1c7bdba3-cd35-4f8b-a546-55b3232457d5}"),
> > +  contractID: "@mozilla.org/secureelement/SEReader;1",
> > +  QueryInterface: XPCOMUtils.generateQI([]),
> > +
> > +  initialize: function initialize(win) {
> 
> now you add function name?
> Use consistent style.
> 
Ok. As I interpreted your prev comment, I thought you wanted me to add 'function name' for all
<identifier>: <function keyword> <function name> (args..) {.... }
Across the DOMSecureElement.js, I have made this consistent with the above syntax.

> @@ +217,5 @@
> > +    this._window = win;
> > +    this._isSEPresent = true;
> > +  },
> > +
> > +  openSession: function openSession() {
> 
> Shouldn't this check this._isSEPresent first?
> 
Agreed. Added this check now
> @@ +218,5 @@
> > +    this._isSEPresent = true;
> > +  },
> > +
> > +  openSession: function openSession() {
> > +    return PromiseHelpers._createSEPromise((aResolverId) => {
> 
> I think you could just update your promiseHelper a bit, 
> you could take 'reader' object when you new your promise, when the promise
> resolves you can get the 'reader' back.
> So no need to StateHelper.
> 
> Same idea for object below.
> 
Seems like a good suggestion. However I am still trying to understand your thoughts completely.
Are you suggesting to completely remove 'SEStatehelper'  ? Or are you suggesting to merge this helper to PromisHelper ? Also if I have understood your comment properly,
Say, if we pass the 'reader' obj at the time 'PromiseHelpers.createSEPromise' and 'PromiseHelpers' can save this value and upon resolving we can get the object back. This means that we are persisting 'readerObj' for Session usecase , And 'sessionObj' for 'channel' etc.. temporarily till the promise is resolved or rejected. However we may also have cases like 'NotifySEPresent' scenarios for which we will have to update respective 'reader obj' state at a later stage. Also similarly for 'closeAll' operations when we have to update 'isClosed' state for a session / channel appropriately. For example if there are multiple channels opened and one of the channels get closed, how would SEManager (in receiveMessage) be able to update that 'channel' state only ? I guess there are ways of achieving this but I am trying to understand your suggestion completely for all use-cases.

> @@ +257,5 @@
> > +  },
> > +
> > +  set isSEPresent(isSEPresent) {
> > +    this._isSEPresent = isSEPresent;
> > +  }
> 
> Wouldn't it be easier if you just define isSEPresent?
> 
Actually, we defined this 'isSEPresent' as 'readonly attribute' in webidl. I think this may prevent us from setting the value to this attribute unless we have setter. Also when I looked at other subs-system implementations of getters and setters on variable, they usually operate on a private member as it happens here.
> @@ +258,5 @@
> > +
> > +  set isSEPresent(isSEPresent) {
> > +    this._isSEPresent = isSEPresent;
> > +  }
> > +};
> 
> Where is 'type' attribute?
> 
Since 'this.type' is set in SEReader's 'initialize function, (one time operation ) whenever Gaia apps say reader.type, apps see the value that was set during 'initialize' operation.
> @@ +268,5 @@
> > + * hosted by the Secure Element.
> > + */
> > +function SESession() {
> > +  this._sessionId = null;
> > +  this.reader = null;
> 
> move this to prototype.
> 
Ok
> @@ +278,5 @@
> > +  classID: Components.ID("{2b1809f8-17bd-4947-abd7-bdef1498561c}"),
> > +  contractID: "@mozilla.org/secureelement/SESession;1",
> > +  QueryInterface: XPCOMUtils.generateQI([]),
> > +
> > +  initialize: function initialize(win, result, data) {
> 
> pass sessionId and type directly.
> 
ok
> @@ +292,5 @@
> > +    // According to SIMalliance_OpenMobileAPI v4 spec,
> > +    // in case of UICC it is recommended to reject the opening of the logical
> > +    // channel without a specific AID.
> > +    if (this.reader.type === SE.TYPE_UICC) {
> > +      if (!aid || aid.length === 0) {
> 
> This check is totally not neccesary because you already check AID in line
> 302.
> 
I have slightly modified the condition.
We need to support following cases
openLogicalChannel(null) // For 'uicc' do not permit this op
openLogicalChannel(null) // For 'eSE' may permit this op and default card applet is selected
> @@ +300,5 @@
> > +    }
> > +
> > +    if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {
> > +      return PromiseHelpers._rejectWithSEError(SE.ERROR_GENERIC +
> > +            " Invalid AID length - " + aid.length);
> 
> The error message doesn't fully match WebIDL.
> 
By modifying webidl comments to explicitly state that passing 'null' aid is allowable only for 'eSE' and not for 'uicc' , Is it ok ?
> @@ +304,5 @@
> > +            " Invalid AID length - " + aid.length);
> > +    }
> > +
> > +    // copy the aid
> > +    this._aid = aid.subarray(0);
> 
> define this in prototype.
> 
ok
> @@ +356,5 @@
> > +    if (this.isClosed) {
> > +      throw new Error(SE.ERROR_BADSTATE + " Session Already Closed!");
> > +    }
> > +  }
> > +};
> 
> remove atr/openBasicChannel from WebIDL.
> 
Ok. I will upload this soon.
> @@ +362,5 @@
> > +/**
> > + * Instance of 'SECommand' dom object represent C-APDU to be sent to a
> > + * secure element.
> > + */
> > +function SECommand() {
> 
> nit, move SECommand after SEChannel
> 
Done
> @@ +368,5 @@
> > +  this.ins = 0x00;
> > +  this.p1 = 0xFF;
> > +  this.p2 = 0xFF;
> > +  this.data = null;
> > +  this.le = -1;
> 
> move these to prototype.
> 
Done
> @@ +372,5 @@
> > +  this.le = -1;
> > +}
> > +
> > +SECommand.prototype = {
> > +  __init: function __init(cla, ins, p1, p2, data, le) {
> 
> check format.
> 
Are you suggesting to not add 'function name' for '__init' ? 
> @@ +394,5 @@
> > + */
> > +function SEChannel() {
> > +  this._aid = null;
> > +  this._channelToken = null;
> > +  this._sessionId = null;
> 
> consistent naming for Token or id.
> 
Addressed
> @@ +395,5 @@
> > +function SEChannel() {
> > +  this._aid = null;
> > +  this._channelToken = null;
> > +  this._sessionId = null;
> > +  this._channelType = "logical";
> 
> Why logical is default?
> 
Made 'basic' the default
> @@ +397,5 @@
> > +  this._channelToken = null;
> > +  this._sessionId = null;
> > +  this._channelType = "logical";
> > +  this.session = null;
> > +  this.openResponse = null;
> 
> move these to prototype.
> 
Done
> @@ +409,5 @@
> > +  classID: Components.ID("{181ebcf4-5164-4e28-99f2-877ec6fa83b9}"),
> > +  contractID: "@mozilla.org/secureelement/SEChannel;1",
> > +  QueryInterface: XPCOMUtils.generateQI([]),
> > +
> > +  initialize: function initialize(win, result, data) {
> 
> pass aid, sessionId directly.
> 
Done
> @@ +417,5 @@
> > +    this._channelType = result.isBasicChannel ? "basic" : "logical";
> > +    // Update the 'channel token' that identifies and represents this
> > +    // instance of the object
> > +    this._channelToken = result.channelToken;
> > +    this.openResponse = Cu.cloneInto(new Uint8Array(result.openResponse), win);
> 
> Why cloneInto?
> 
I think 'cloneInto' gives a better option for object defined in a privileged scope ('result.openResponse' ) and make a reference to it in a less-privileged scope. My two cents! In a way , I guess it is better than __exposed_props.
> @@ +425,5 @@
> > +
> > +  transmit: function transmit(command) {
> > +    this._checkClosed();
> > +
> > +    let dataLen = (!command.data) ? 0 : command.data.length;
> 
> check if command is null/undefined first.
> and let dataLen = command.data ? command.data.length : 0;
> 
Ok changes the condition.
> @@ +437,5 @@
> > +      cla: command.cla,
> > +      ins: command.ins,
> > +      p1: command.p1,
> > +      p2: command.p2,
> > +      data: (!command.data) ? null : command.data,
> 
> data: command.data || null
> 
Ok. Nice
> @@ +510,5 @@
> > +    if (this.isClosed) {
> > +      throw new Error(SE.ERROR_BADSTATE +" Channel Already Closed!");
> > +    }
> > +  }
> > +};
> 
> Where is session defined?
> 
Not sure if I have understood this comment. 
> @@ +520,5 @@
> > +function SEResponse() {
> > +  this.sw1 = 0x00;
> > +  this.sw2 = 0x00;
> > +  this.data = null;
> > +  this.channel = null;
> 
> move these to prototype.
> 
ok
> @@ +529,5 @@
> > +  contractID: "@mozilla.org/secureelement/SEResponse;1",
> > +  QueryInterface: XPCOMUtils.generateQI([]),
> > +
> > +  initialize: function initialize(result, data) {
> > +    this.data = result.simResponse ?
> 
> the response should be conforming to ISO 7816-4, so 'sim' prefix should be
> removed.
> 
Removed!
> @@ +551,5 @@
> > +
> > +  _window: null,
> > +
> > +  classID: Components.ID("{4a8b6ec0-4674-11e4-916c-0800200c9a66}"),
> > +  contractID: "@mozilla.org/navigatorSEManager;1",
> 
> @mozilla.org/secureelement/SEManager;1
> 
Ok. Will modify webidl suitably soon.
> @@ +554,5 @@
> > +  classID: Components.ID("{4a8b6ec0-4674-11e4-916c-0800200c9a66}"),
> > +  contractID: "@mozilla.org/navigatorSEManager;1",
> > +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
> > +                                         Ci.nsISupportsWeakReference,
> > +                                         Ci.nsIObserver]),
> 
> where did you implement nsIObserver?
> 
I think we need to implement 'nsIObserver' otherwise it will fail-safe.
This is needed if we inherit from  'DOMRequestIPCHelper'. Other-wise if not inherited, I think it is better to handle 'inner-window-destroyed' topic etc.. but since DOMRequestIPCHelper takes care of these scenarios, and simply calls 'uninit()' it gives a way to gracefully clean-up things in DOM 
> @@ +580,5 @@
> > +
> > +    this.initDOMRequestHelper(win, messages);
> > +  },
> > +
> > +  uninit: function uninit() {
> 
> who calls this?
 This function will be called from DOMRequestIPCHelper.
> 
> @@ +604,5 @@
> > +  },
> > +
> > +  receiveMessage: function(aMessage) {
> > +    let result = aMessage.json.result;
> > +    let data = aMessage.json.metadata;
> 
> aMessage.data
> 
ok
> @@ +619,5 @@
> > +    }
> > +
> > +    switch (aMessage.name) {
> > +      case "SE:GetSEReadersResolved":
> > +        let availableReaders = [];
> 
> why not just call it 'readers'?
> 
Done
> @@ +621,5 @@
> > +    switch (aMessage.name) {
> > +      case "SE:GetSEReadersResolved":
> > +        let availableReaders = [];
> > +        for (let i = 0; i < result.readers.length; i++) {
> > +          chromeObj = new SEReader(result.readers[i]);
> 
> What's this? you forgot .type ?
> It doesn't match line 205.
> 
Changed the naming convention
> @@ +680,5 @@
> > +      case "SE:CloseChannelRejected":
> > +      case "SE:TransmitAPDURejected":
> > +      case "SE:CloseAllByReaderRejected":
> > +      case "SE:CloseAllBySessionRejected":
> > +        let error = data.error ? data.error : SE.ERROR_GENERIC;
> 
> data.error || SE.ERROR_GENERIC
> 
Ok.
> @@ +683,5 @@
> > +      case "SE:CloseAllBySessionRejected":
> > +        let error = data.error ? data.error : SE.ERROR_GENERIC;
> > +        resolver.reject(error);
> > +        break;
> > +      case "SE:NotifySEPresent":
> 
> check permission.
Sorry, not sure if I have understood this comment. What permission should be enforced here?
(Assignee)

Comment 159

3 years ago
Created attachment 8541403 [details] [diff] [review]
Part 2: (v2.2a) Secure Element DOM Implementation

Uploading DOM changes with comments addressed thus far. Parent process side changes will follow soon. Thanks
Attachment #8539867 - Attachment is obsolete: true
Attachment #8541403 - Flags: feedback?(allstars.chh)
(In reply to Siddartha P from comment #158)
> > @@ +212,5 @@
> > > +  classID: Components.ID("{1c7bdba3-cd35-4f8b-a546-55b3232457d5}"),
> > > +  contractID: "@mozilla.org/secureelement/SEReader;1",
> > > +  QueryInterface: XPCOMUtils.generateQI([]),
> > > +
> > > +  initialize: function initialize(win) {
> > 
> > now you add function name?
> > Use consistent style.
> > 
> Ok. As I interpreted your prev comment, I thought you wanted me to add
> 'function name' for all
> <identifier>: <function keyword> <function name> (args..) {.... }
> Across the DOMSecureElement.js, I have made this consistent with the above
> syntax.
> 
I mean use whatever style you like, just use it consistenly.
And in your latest patch you still use different style, please fix this.

> > @@ +683,5 @@
> > > +      case "SE:CloseAllBySessionRejected":
> > > +        let error = data.error ? data.error : SE.ERROR_GENERIC;
> > > +        resolver.reject(error);
> > > +        break;
> > > +      case "SE:NotifySEPresent":
> > 
> > check permission.
> Sorry, not sure if I have understood this comment. What permission should be
> enforced here?

I thought there are some onsepresent/onseremoved callbacks but it turns out it does not.
So please removed this for this bug and file a seperate bug for this.
Comment on attachment 8541403 [details] [diff] [review]
Part 2: (v2.2a) Secure Element DOM Implementation

Review of attachment 8541403 [details] [diff] [review]:
-----------------------------------------------------------------

I'll review when you upload Parent process part and WebIDL part.
I need to cross reference them.

::: dom/secureelement/DOMSecureElement.js
@@ +596,5 @@
> +                      "SE:CloseChannelRejected",
> +                      "SE:TransmitAPDURejected",
> +                      "SE:CloseAllByReaderRejected",
> +                      "SE:CloseAllBySessionRejected",
> +                      "SE:NotifySEPresent"];

I think for the "SE:CloseXXX" messages, most of them could be removed.
As SEReader, SESession are just objects on the DOM part,
on the parent process it should just have information about reader type and channel ID.
After all what the reader.close does is to close the sessions that reader opened, not actually *close* the reader.
(And there's no reader.open() either)

So SEReader should keep a list of sessions it opened, and in turn SESession should keep a list of channels opened.
This should be done together with modifying your PromiseHelper as I said before.

And when a reader.close() is called, 
the DOM side could just

SEReader_Close() {
  for (let session of this.sessions) {
    session.close();
  }
}

SESession_Close() {
  for (let channel of this.channels) {
    channel.close()
  }
}

SEChannel_Close() {
  SendAsyncMesage("SE:CloseChannel", {
     channelId: ....
  });
}

And you could just maintain a list of open channels in DOM, instead of maintaining a table of reader, sessions, channels,... etc.
Attachment #8541403 - Flags: feedback?(allstars.chh)
Created attachment 8542142 [details] [diff] [review]
Part 6: (v1.2) SEUtils.jsm + nits, r=allstars.chh

Nits fixed. Setting to r+, since it was positively reviewed by Yoshi in comment 157.
Attachment #8541241 - Attachment is obsolete: true
Attachment #8542142 - Flags: review+

Comment 163

3 years ago
Can we update the target milestone and ETA? Thanks!
Flags: needinfo?(whuang)
Due to hardware limitation, we don't support embedded security element until we have a new reference device.
No longer depends on: 1030615
(Assignee)

Comment 165

3 years ago
Created attachment 8544357 [details] [diff] [review]
Part 1 : (v1.10a) Secure Element APIs - Inital Draft

Hi Ehsan, If I may request you to review the changes, one more time pls.
- Removed the interface 'openBasicChannel' and 'atr' attribute as it is not supported by SE stack. We should hold discussions with vendor in order to support these.
- Added explicit comments on 'aid' length + nits
Attachment #8533051 - Attachment is obsolete: true
Attachment #8544357 - Flags: review?(ehsan)
(Assignee)

Comment 166

3 years ago
(In reply to Siddartha P from comment #165)
> Created attachment 8544357 [details] [diff] [review]
> Patch 1 : (v1.10a) Secure Element APIs - Inital Draft
> 
> Hi Ehsan, If I may request you to review the changes, one more time pls.
> - Removed the interface 'openBasicChannel' and 'atr' attribute as it is not
> supported by SE stack. We should hold discussions with vendor in order to
> support these.
> - Added explicit comments on 'aid' length + nits

Here is the diff between this version and previous ver
https://bugzilla.mozilla.org/attachment.cgi?oldid=8533051&action=interdiff&newid=8544357&headers=1
(Assignee)

Updated

3 years ago
Attachment #8544357 - Attachment description: Patch 1 : (v1.10a) Secure Element APIs - Inital Draft → Part 1 : (v1.10a) Secure Element APIs - Inital Draft
(Assignee)

Comment 167

3 years ago
Created attachment 8544358 [details] [diff] [review]
Part 1.a: (v1) Add new permission to table - 'secureelement-manage'

Requesting a review for this patch as well. Perhaps it goes with webidl review.
Thanks.
Attachment #8544358 - Flags: review?(ehsan)
(Assignee)

Comment 168

3 years ago
Created attachment 8544364 [details] [diff] [review]
Part 4: (v4.2) Add moz.build for SecureElement files required for part 2 & 3 patches. r=yoshi
Attachment #8539856 - Attachment is obsolete: true
Attachment #8544364 - Flags: review?(allstars.chh)
(Assignee)

Comment 169

3 years ago
Created attachment 8544366 [details] [diff] [review]
Part 2: (v2.3) Secure Element DOM Implementation

I think I addressed almost all your comments. The main difference being, 
- Now CreateSEPromise()  can hold the context and therefore there is no need of SEStateHelper at all.
- Also updated 'close' behavior across instances. If the parent is closed, it notifies its children to update its 'state' as well.
- Added 'isSEPresent' IPC (sendSyncMessage) to parent process. Since we may have to evaluate additions of a new idl 'onseremoved' 'onseadded', I hope this change is ok for now.
Attachment #8541403 - Attachment is obsolete: true
Attachment #8544366 - Flags: review?(allstars.chh)
(Assignee)

Comment 170

3 years ago
Created attachment 8544369 [details] [diff] [review]
Part 3: (v3.4) Secure Element Parent process Implementation. r=yoshi

Main differences between this version w.r.t previous one are:-
- Added the new idl nsISecureElementConnector.idl that could be used by ACE module (or any other parent process module).
- UiccConnector is 'clientId' aware
- Modified isValidSession() and 'getChannel()' and removed isValidAID and added instead 'isValidChannelToken()'
- All the UiccConnector public methods namely doOpenChannel() , doCloseChannel() and doTransmit() are consistent in their responses (through 'nsISEChannelCallback' ) to both external modules ('SecureElementConnector' that implements 'nsISecureElementConnector' ) AND internal module 'SecureElementManager' (Note that 'SecureElementManager' functions 'openChannel' , ' transmit' and 'closeChannel' call into UiccConnectors  doOpenChannel() , doTransmit(), doCloseChannel() respectively.
Attachment #8539927 - Attachment is obsolete: true
Attachment #8544369 - Flags: review?(allstars.chh)
(Assignee)

Comment 171

3 years ago
Created attachment 8544370 [details] [diff] [review]
Part 5: (v5.1) Add build support for SE feature
Attachment #8533084 - Attachment is obsolete: true
Attachment #8544370 - Flags: review?(allstars.chh)
Blocks: 1118096
Blocks: 1118097
Blocks: 1118098
Blocks: 1118099
Blocks: 1118101
Blocks: 1118102
Blocks: 1118106
Hi Sid, I have applied patches part 1~5 successfully. But patch part 6 needs to rebase. Can you help to rebase it?
Flags: needinfo?(psiddh)
Comment on attachment 8544366 [details] [diff] [review]
Part 2: (v2.3) Secure Element DOM Implementation

Review of attachment 8544366 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/secureelement/DOMSecureElement.js
@@ +80,5 @@
> +
> +  rejectWithSEError: function rejectWithSEError(aReason) {
> +    return this.createSEPromise((aResolverId) => {
> +      debug("SEError: " + aReason);
> +      this.takePromiseResolver(aResolverId).reject(aReason);

Should reject Error, not String.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject

@@ +101,5 @@
> +  _window: null,
> +
> +  _sessions: [],
> +
> +  type: SE.TYPE_UICC,

should be null.

@@ +104,5 @@
> +
> +  type: SE.TYPE_UICC,
> +
> +  classID: Components.ID("{1c7bdba3-cd35-4f8b-a546-55b3232457d5}"),
> +  contractID: "@mozilla.org/secureelement/SEReader;1",

For contractID the style is all lower-case.

@mozilla.org/secureelement/reader,
same for other objects.

@@ +127,5 @@
> +       * resolverId  : ID that identifies this IPC request.
> +       * type        : Type identifying the session instance ('uicc' / 'eSE')
> +       * appId       : Current appId obtained from 'Principal' obj
> +       */
> +      cpmm.sendAsyncMessage("SE:OpenSession", {

Open Session shouldn't invoke IPC.
I think I mentioned this before.

@@ +144,5 @@
> +       * resolverId  : ID that identifies this IPC request.
> +       * type        : Type identifying the session instance ('uicc' / 'eSE')
> +       * appId       : Current appId obtained from 'Principal' obj
> +       */
> +      cpmm.sendAsyncMessage("SE:CloseAllByReader", {

ditto, I think I mentioned this before.

@@ +156,5 @@
> +  get isSEPresent() {
> +    return cpmm.sendSyncMessage("SE:IsSEPresent", {
> +      type: this.type,
> +      appId: this._window.document.nodePrincipal.appId
> +    });

This shouldn't trigger IPC.

For the simplest way, this value can be set in getSEReaders();
and you can update that attribute in follow-up bug.

@@ +159,5 @@
> +      appId: this._window.document.nodePrincipal.appId
> +    });
> +  },
> +
> +  receiveMessage: function receiveMessage(aMessage) {

message.
or make all arguments in this file prefix with 'a'.

This function shouldn't be named 'receiveMessage', as this object doesn't process IPC at all,
it could be named like 'processMessage' to prevent confusion with nsIMessageManager.

@@ +199,5 @@
> +
> +  reader: null,
> +
> +  classID: Components.ID("{2b1809f8-17bd-4947-abd7-bdef1498561c}"),
> +  contractID: "@mozilla.org/secureelement/SESession;1",

ditto, lower-case.

@@ +227,5 @@
> +      if (this.reader.type === SE.TYPE_UICC) {
> +        return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
> +                                                " AID is not specified!");
> +      }
> +    } else if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {

I think I mentioned this before.
The first 'if' seems not neccesary.

@@ +229,5 @@
> +                                                " AID is not specified!");
> +      }
> +    } else if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {
> +      return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
> +            " Invalid AID length - " + aid.length);

align " with P

@@ +232,5 @@
> +      return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
> +            " Invalid AID length - " + aid.length);
> +    } else {
> +      // copy the aid
> +      this._aid = aid.subarray(0);

Where is this._aid being used?

@@ +248,5 @@
> +       * appId       : Current appId obtained from 'Principal' obj
> +       */
> +      cpmm.sendAsyncMessage("SE:OpenChannel", {
> +        resolverId: aResolverId,
> +        aid: this._aid,

if this._aid is not used, we could simply supply aid here.

@@ +293,5 @@
> +      channel.isClosed = true;
> +    }
> +    this._isClosed = isClosed;
> +    // Reset the sessionToken
> +    this._sessionToken = null;

These attributes (_channels_, _sessionToken) shouldn't be done in setter.

@@ +296,5 @@
> +    // Reset the sessionToken
> +    this._sessionToken = null;
> +  },
> +
> +  receiveMessage: function receiveMessage(aMessage) {

ditto. rename function name and aMessage.

@@ +302,5 @@
> +      case "SE:OpenChannelResolved":
> +        this._channels.push(aMessage.childContext);
> +        break;
> +      case "SE:CloseAllBySessionResolved":
> +        this.isClosed = true;

attributes should be set here.

@@ +355,5 @@
> +    this._sessionToken = sessionToken;
> +    this._aid = aid;
> +    // Update 'session' obj
> +    this.session = sessionCtx;
> +    this.openResponse = Cu.cloneInto(new Uint8Array(openResponse), win);

Is 'new Uint8Array' neccesary?

@@ +375,5 @@
> +      cla: command.cla,
> +      ins: command.ins,
> +      p1: command.p1,
> +      p2: command.p2,
> +      data: command.data || null,

is || null neccesary?

@@ +439,5 @@
> +
> +  set isClosed(isClosed) {
> +    this._isClosed = isClosed;
> +    // Reset the channelToken
> +    this._channelToken = null;

ditto

@@ +444,5 @@
> +  },
> +
> +  receiveMessage: function receiveMessage(aMessage) {
> +    switch (aMessage.name) {
> +      case "SE:TransmitAPDUResolved": // Do nothing

nothing?

From WebIDL it says Promise<SEResponse>
Where is the response ?

Oh I found it in line 643.
So this is totally strange as it seems you process those messages twice.

The messages should be processed once, and if it has some extra data needs to be processed, you should add a method for that.
Attachment #8544366 - Flags: review?(allstars.chh) → review-
Comment on attachment 8544369 [details] [diff] [review]
Part 3: (v3.4) Secure Element Parent process Implementation. r=yoshi

Review of attachment 8544369 [details] [diff] [review]:
-----------------------------------------------------------------

UICC implementation should be moved to another part.

::: dom/secureelement/gonk/SecureElement.js
@@ +85,5 @@
> +      case SE.TYPE_UICC:
> +        return UiccConnector;
> +      case SE.TYPE_ESE:
> +      default:
> +        if (DEBUG) debug('UnSupported SEConnector : ' + type);

Double quote.

@@ +173,5 @@
> +
> +    // Register the new SecureElement target.
> +    registerSecureElementTarget: function(message, readers) {
> +      let appInfoMap = this.appInfoMap;
> +      let appId = message.json.appId;

message.data, json is deprecated.

@@ +621,5 @@
> +      // Note that 'aid' is a string, and therefore max length = SE.MAX_AID_LEN * 2
> +      if (aidLen < SE.MIN_AID_LEN || aidLen > SE.MAX_AID_LEN * 2) {
> +        debug("Invalid AID length : " + aidLen);
> +        throw new Error(SE.ERROR_GENERIC);
> +      }

AID check has been done in DOM.

::: dom/secureelement/gonk/nsISecureElementConnector.idl
@@ +63,5 @@
> +    *        Application Identifier of the Card Applet on the secure element.
> +    * @param callback
> +    *        callback to notify the result of the operation.
> +    */
> +    void seOpenChannel(in short type,

remove all 'se' prefix.
Attachment #8544369 - Flags: review?(allstars.chh)
Created attachment 8544705 [details] [diff] [review]
Part 6: (v1.3) SEUtils.jsm + nits, r=allstars.chh

Here is the rebased version of part 6. r+ was granted in comment 157 by Yoshi.
Flags: needinfo?(psiddh)
Attachment #8544705 - Flags: review+
Attachment #8542142 - Attachment is obsolete: true
Comment on attachment 8544358 [details] [diff] [review]
Part 1.a: (v1) Add new permission to table - 'secureelement-manage'

Review of attachment 8544358 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/apps/PermissionsTable.jsm
@@ +423,5 @@
>                               additional: ["settings-api"]
> +                           },
> +                           "secureelement-manage": {
> +                             app: DENY_ACTION,
> +                             privileged: ALLOW_ACTION,

You also need a trusted entry which you probably want to set to deny.  Looking at the context for the diff, it seems like you are on a very old tree, please rebase on top of a recent tree in order to avoid excessive issues and changes as you get closer to landing.
Attachment #8544358 - Flags: review?(ehsan) → review-
Attachment #8544357 - Flags: review?(ehsan) → review+
Comment on attachment 8544369 [details] [diff] [review]
Part 3: (v3.4) Secure Element Parent process Implementation. r=yoshi

Review of attachment 8544369 [details] [diff] [review]:
-----------------------------------------------------------------

Plesae re-check your implementation again
as I found many things could be done in Content side, and many code are just error-handling.

Also check the style again as I found there are some style error, like using single quote, no braces {}, and indent.
I have mentioned many times.

::: dom/secureelement/gonk/SecureElement.js
@@ +120,5 @@
> +    /*
> +    ------------------------------
> +       Structure of 'appInfoMap':
> +    ------------------------------
> +    {[appId :// (key = '1020')

I still don't understand what's appId for here?

@@ +123,5 @@
> +    ------------------------------
> +    {[appId :// (key = '1020')
> +        target         : msg.target
> +        readerTypes    : [] // 'uicc','eSE'
> +        sessions       : {

no sessions.

@@ +452,5 @@
> +    },
> +
> +    /*
> +    // Uncomment this function in order to debug the 'gMap'.
> +    log: function(event) {

who calls this?
remove it if no used at all.

@@ +569,5 @@
> +
> +    // Initializes iccListener context per clientId to monitor UICC state
> +    start: function() {
> +      this._numClients = Cc["@mozilla.org/ril;1"].
> +                         getService(Ci.nsIRadioInterfaceLayer).numRadioInterfaces;

Doesn't flame have two RadioInterfaces?
So you plan to do multi-SIM here?

You could only use the one working with UICC-SE for now.

@@ +642,5 @@
> +          });
> +        },
> +
> +        notifyError: function(reason) {
> +          debug('Failed to open the channel to AID : ' + aid +

double quote.

@@ +685,5 @@
> +        p3 = command.data.length; // lc
> +      } else if (command.le !== -1) {
> +        // Only le is set. 'p3=le'. Response expected!
> +        p3 = command.le;
> +      }

I think I have commented this before.

@@ +696,5 @@
> +      }
> +
> +      if (((cla & (0xFF & 0x80) === 0)) &&
> +          ((0xFF & (cla & (0xFF & 0x60))) !== (0xFF & 0x20))) {
> +        if (ins === (0xFF & SE.INS_MANAGE_CHANNEL)) {

I don't know what are those 0xff for
As I said if you'd like to check the type, use IDL.

@@ +775,5 @@
> +    // Closes all the channels on given clientId.
> +    doCloseAll: function(clientId, channels, callback) {
> +      this._checkPresence(clientId);
> +
> +      let closedChannels = [];

I don;t know what's this, but if you need another array, allocate it when needed.

@@ +787,5 @@
> +
> +      let count = 0;
> +      for (let index = 0; index < channels.length; index++) {
> +        let channel = channels[index];
> +        if (channel === SE.BASIC_CHANNEL) {

do this check in Content.

@@ +1292,5 @@
> +    // 1. Check if the type is already a supported one
> +    //          AND
> +    // 2. Check if the 'session type' that content is attempting to connect to is
> +    //    in a 'present state' by queriying the appropriate 'connector obj'.
> +    if (gMap.isSupportedReaderType(msg.json) &&

I totally don't understand what you're doing here.
At least I think the check should be done in getSEReaders, not in openSession.

What would we allow an app getting a reader but no permission for doing anything?

@@ +1293,5 @@
> +    //          AND
> +    // 2. Check if the 'session type' that content is attempting to connect to is
> +    //    in a 'present state' by queriying the appropriate 'connector obj'.
> +    if (gMap.isSupportedReaderType(msg.json) &&
> +      this.connectorFactory.getConnector(msg.json.type).isSEPresent(PREFERRED_UICC_CLIENTID)) {

isSEPresent is already checked in content.

@@ +1455,5 @@
> +  },
> +
> +  _ensureParentProcess: function() {
> +    if (!this._isParentProcess) {
> +      throw new Error(SE.ERROR_SECURITY +

Why would child process load this file ?

Even it could, you should throw in the first place.

::: dom/secureelement/gonk/nsISecureElementConnector.idl
@@ +14,5 @@
> +   *        The Channel Number/Handle that is successfully opened.
> +   * @param openResponse
> +   *        Response from SE for OpenChannel operation.
> +   */
> +  void notifyOpenChannelSuccess(in long channel, in DOMString openResponse);

DOMString?

@@ +65,5 @@
> +    *        callback to notify the result of the operation.
> +    */
> +    void seOpenChannel(in short type,
> +                       in unsigned long clientId,
> +                       in DOMString aid,

This should be some TypedArray according to your WebIDL.

@@ +95,5 @@
> +    * @param callback
> +    *        callback to notify the result of the operation.
> +    */
> +    void seExchangeAPDU(in short type,
> +                        in unsigned long clientId,

I am not sure I understand the proposal here.

Will RIL, and NFC represent an instance of Connector?
Or there's only 1 connector that could connect to RIL and NFC?

If it's former 'type' argument could be omited.
And if it's latter, it seems to me this interface is an interface of SecureElementManager.

::: dom/secureelement/gonk/se_consts.js
@@ +30,5 @@
> +
> +this.TYPE_BASIC_CHANNEL = "basic";
> +this.TYPE_LOGICAL_CHANNEL = "logical";
> +
> +this.BASIC_CHANNEL = 0;

What's the difference from line 31?
Attachment #8544369 - Flags: review-
I think the quality of the patch is not so well given that it should have been worked for a long period.
And I still found out I am reviewing the same patch without problems/questions addressed again and again, and I guess it would be like WebNFC (Bug 674741) again, so I have to emphasize the code review process again:

1. Mozilla code base is an open source software so everyone in the world could get your patch, so only you understand the code is not enough, we should make the code to be easily read by most engineers.

2. And what's more importmant is that "Oh the code works" is not enough, but *"Oh the code is simple and clear so it's easy to see that it will work"*.

So if you write a hugh patch like this but there are many unclear or maybe unneccesary things, I will look it over and over again until I can make sure it's working. And the process will cause you and me a lot of time.

But if you prepare some interfaces for your code, and give detail explanation for it, I can easily guess what's your implementation is going to do by reading your interface, I propably r+ your patch in the first place, and leave some implemetation problems to other bugs.

So please do re-check your patch, and re-think again before submitting next r?
If I still find something problematic I will immediately r- on that without spending too much time on this.

Thanks
(Assignee)

Comment 179

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #178)
> I think the quality of the patch is not so well given that it should have
> been worked for a long period.
> And I still found out I am reviewing the same patch without
> problems/questions addressed again and again, and I guess it would be like
> WebNFC (Bug 674741) again, so I have to emphasize the code review process
> again:
> 
> 1. Mozilla code base is an open source software so everyone in the world
> could get your patch, so only you understand the code is not enough, we
> should make the code to be easily read by most engineers.
> 
> 2. And what's more importmant is that "Oh the code works" is not enough, but
> *"Oh the code is simple and clear so it's easy to see that it will work"*.
> 
> So if you write a hugh patch like this but there are many unclear or maybe
> unneccesary things, I will look it over and over again until I can make sure
> it's working. And the process will cause you and me a lot of time.
> 
> But if you prepare some interfaces for your code, and give detail
> explanation for it, I can easily guess what's your implementation is going
> to do by reading your interface, I propably r+ your patch in the first
> place, and leave some implemetation problems to other bugs.
> 
> So please do re-check your patch, and re-think again before submitting next
> r?
> If I still find something problematic I will immediately r- on that without
> spending too much time on this.
> 
> Thanks

Ok Yoshi, Let me try to reiterate what I have been doing through these patches!

1) Child process / DOM Side : This part of stack does not deal with protocol related details. It only deals with creation of promises and managing them. DOM side implementation is mostly a transient pipe from Gaia Apps to Parent process with very basic sanity checks in place. Since we are dealing with Wallet (like apps) , security has to be the main reason behind the design as the assumption is that content process could be compromised anytime. With that premise, lot of details are hidden in parent and not in child.

2) Parent Process : This handles all the protocol related details as well as book keeping of various sessions , channels per application. As you may see it has multiple objects

2.a) SEConnectorFactory : This is primarily responsible for getting a 'connector object' (Ex: Say, UiccConnector) based on the 'type'.

2.b) gMap : 
This is the object that exposes functions mainly for book-keeping activities.
As you may know, An application (appID) can open multiple sessions. And each session can open multiple channels.
This map helps to track all of this per given appID. Similarly multiple apps can open sesssions (and in turn channels) simultaneously.

For ex:- When Gaia apps issue the following steps
STEP 1 : readers[0].openSession()  , DOM implementation sends this request to Chrome / Parent process using
standard IPC mechanism. Parent process generates an unique uuid (sessionId) and responds to DOM impl. DOM then resolves the promise with a new session obj.
STEP 2: Gaia app can potentially issue readers[0].openSession() any number of times. All the session objects created in DOM are identified by a
unique uuid in parent process.
Say @ STEP 3: Gaia app says, session.OpenLogicalChannel(...), DOM implementation sends this request to the parent process. Parent process using a connector obj (UiccConnector)
opens a channel. Upon successfully opening a channel, a channel number is returned (Ex: '1' or '2' or '3' or '4'.) Since these channel numbers are internal details, parent process
creates a 'channelToken' (unique uuid) and returns it to DOM implementation instead of actual 'channel Number'. Note that this channel is tied to a session. A channel cannot be opened
w/o opening a session. All of this data is maintained in this map object and therefore all of this functions deal with only map management (such as registerSecureElementTarget, 
 UnregisterSecureElementTarget addSession, deleteSession, isValidSession, addChannel, removeChannels isValidChannelToken etc etc)

2.c) SecureElementManager : This is the main object of the parent process. This acts as an entry point as well. It handles all the IPC from Content target and based on the type (uicc / eSE) , it gets the appropriate 'Connector obj' using 'SEConnectorFactory' i;e if the reader is 'uicc' type then it talks to 'UiccConnector' for all low level operations

One example flow:
[Gaia App] reader[0].session.OpenLogicalChannel(...) --> [SE DOM Impl] CreatePromise (type = 'uicc', aid..) 
--> [SE Parent process] SecureElementManager handles the IPC request. 
--> [SE Parent process] SecureElementManager checks with 'gMap' if it is a valid ongoing session first 
-->  [If Yes] --> SEConnectorFactory.getConnector(type) (In this case we get 'UiccConnector') 
--> UiccConnector.doOpenChannel(...)--> RIL IccProvider openChannel.

2.d) SecureElementConnector: This implements the newly designed nsISecureElementConnector idl. This is in place only for external modules such as ACE. (Integration with ACE)
However this obj also talks to Connector obj (Say UiccConnector) based on the 'type'. If a new SE is added tomorrow, it can easily be pulgged in with no extra code.
All said, based on one of your comments, This object need not be stand-alone and instead it could be implemented by 'SecureElementManager' itself. I will remove this in the next patch.

2.e) UiccConnector: As you may see, this object is agnostic as far as internal module (SecureElementManager) or external module (SecureElementConnector) accessing its functions such as
doOpenChannel(..), doTransmit(..) , doCloseChannel(...). This object maintains this kind of consistency because it expects clients (users) of this object to implement the callback 'nsISEChannelCallback' for all the three functions.There are other functions as well , but the mentioned three are the most important ones. 
This obj also holds 'IccListenerCtx' per clientID. But since you have strongly opined not to add this part , I am ok with removing it and only supporting one clientID for now.

Note: With the above design, if and when new secure element support is to be implemented , say 'eSEConnector', all that this new connector object has to implement is
doOpenChannel(), doTransmit() and doCloseChannel() and doCloseAll(). And obviously this implementation should be talking to something like nfcProvider or some such (on the lines of
iccProvider). Everything else would work as-is. There is no need to modify DOM impl, or gMap or nsISecureElementConnector.idl or even SecureElementManager.
(Assignee)

Comment 180

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #178)
> I think the quality of the patch is not so well given that it should have
> been worked for a long period.
> And I still found out I am reviewing the same patch without
> problems/questions addressed again and again, and I guess it would be like
> WebNFC (Bug 674741) again, so I have to emphasize the code review process
> again:
> 
I think I have been addressing 80 - 90% of your comments every-time in the couple of reviews happened for both DOM & Parent process implementation. As far as remaining 10 - 20% of the un-addressed comments, perhaps I am not able to articulate my thoughts very well leaving some gaps in understanding (or) perhaps I don't fully understand your comments. Whatever be it, there is no denying that I have read, tried to grasp each and every comment of yours thus far. 
I think you have mentioned the following points couple of times which I haven't addressed so far
1 In DOM , openSession(..) , closeXXX(..) operations need not be IPC based. 
 1.a) I think this may not be the ideal way given the current design. Because when a session is opened, a unique UUID is generated by parent process and is added to 'gMap' object so that it can perform validation / sanity checks whenever this newly created session object tries to attempt session related operations.
 1.b) Similarly say closeAllByReader(..) has to be performed in parent process as it closes all the channels using the connector object. Once this operation is completed, its result is notified to DOM and it then is resolved or reject based on the result.
 1.c) IsSEPresent: I agree with you that we should remove the IPC impl. for this one. I only retained it because, Alison's QA test app has more than couple of test cases around this attribute, that may result in failures. I thought that maybe we can live with this IPC implementation for now and raise a follow-up bug and implement it later. But I guess we can live with failures in QA test app for now maybe. I will remove it as per your suggestion.

2) Also you were advocating to remove all sanity & error checks from parent process and mostly move it to DOM part.
 2.a) I think we should have very basic checks in DOM while parent has to do all protocol related sanity & other error checks. There are some cases, I think like 'aid length' where it is better to have at both places. One reason being,  that this part of parent process not only caters to DOM IPC request coming from Gaia apps but also from external module such as ACE could be possibly passing the AID as well using nsISecureElementConnector.idl. Also if the content is compromised, and with no complete checks in place in parent process can lead to some security issues possibly.

3) Based on some of your latest comments# 173, 174 & 177, I will make some more changes to both DOM and parent process.

4) In particular you have made this @ comment#177 "Also check the style again as I found there are some style error, like using single quote, no braces {}, and indent. I have mentioned many times."
 - I will definitely take a closer look at this again, but for this one I offer no excuses.

> 1. Mozilla code base is an open source software so everyone in the world
> could get your patch, so only you understand the code is not enough, we
> should make the code to be easily read by most engineers.
> 
> 2. And what's more importmant is that "Oh the code works" is not enough, but
> *"Oh the code is simple and clear so it's easy to see that it will work"*.
> 
> So if you write a hugh patch like this but there are many unclear or maybe
> unneccesary things, I will look it over and over again until I can make sure
> it's working. And the process will cause you and me a lot of time.
> 
> But if you prepare some interfaces for your code, and give detail
> explanation for it, I can easily guess what's your implementation is going
> to do by reading your interface, I propably r+ your patch in the first
> place, and leave some implemetation problems to other bugs.
> 
Ok. I will try to add more comments and try to explain things clearly. I will also try to make it more simple as you said. Do you think some kind of face-to-face video call or even an IRC chat session is a good idea ?  Because a lot of this is simply lost in translation or typing long responses. Or do you think some kind of design doc is useful, I am not sure. Please suggest.

As per you latest suggestion I will do the following apart from other review comments
1. Remove 'IccListenerCtx' 
2. Merge SecureElementConnector with SecureElementManager and remove  unnecessary 'ensureParentProcess()'
3. Remove IsSEPresent IPC impl
4. Revisit error check scenarios in Parent process along with coding style.

> So please do re-check your patch, and re-think again before submitting next
> r?
I will , to the best of my ability.
> If I still find something problematic I will immediately r- on that without
> spending too much time on this.
> 
> Thanks
(Assignee)

Comment 181

3 years ago
(In reply to Yoshi Huang[:allstars.chh] from comment #173)
> Comment on attachment 8544366 [details] [diff] [review]
> Part 2: (v2.3) Secure Element DOM Implementation
> 
Acknowledging all the comments made so far , answering only some of them in-line while others will be fixed in the next patch.  
> Review of attachment 8544366 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: dom/secureelement/DOMSecureElement.js
> @@ +80,5 @@
> > +
> > +  rejectWithSEError: function rejectWithSEError(aReason) {
> > +    return this.createSEPromise((aResolverId) => {
> > +      debug("SEError: " + aReason);
> > +      this.takePromiseResolver(aResolverId).reject(aReason);
> 
> Should reject Error, not String.
> See
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
> Global_Objects/Promise/reject
> 
Ok . I do this now : reject (new error(aReason)). That said, I think it is syntactically ok to reject with simply a string, I guess. (Per Promise.webidl, the attribute is 'any'). Anyways I have now made the change as you suggested.

> @@ +101,5 @@
> > +  _window: null,
> > +
> > +  _sessions: [],
> > +
> > +  type: SE.TYPE_UICC,
> 
> should be null.
> 
Ok
> @@ +104,5 @@
> > +
> > +  type: SE.TYPE_UICC,
> > +
> > +  classID: Components.ID("{1c7bdba3-cd35-4f8b-a546-55b3232457d5}"),
> > +  contractID: "@mozilla.org/secureelement/SEReader;1",
> 
> For contractID the style is all lower-case.
> 
> @mozilla.org/secureelement/reader,
> same for other objects.
> 
Ok
> @@ +127,5 @@
> > +       * resolverId  : ID that identifies this IPC request.
> > +       * type        : Type identifying the session instance ('uicc' / 'eSE')
> > +       * appId       : Current appId obtained from 'Principal' obj
> > +       */
> > +      cpmm.sendAsyncMessage("SE:OpenSession", {
> 
> Open Session shouldn't invoke IPC.
> I think I mentioned this before.
> 
I hope comment#180 , 1.b) clarifies your question. If we don't do a openSession, with parent process, the it may be difficult to manage channels that get opened in a session and book-keep in parent process. I am not sure if I am missing anything here. Please do correct.
> @@ +144,5 @@
> > +       * resolverId  : ID that identifies this IPC request.
> > +       * type        : Type identifying the session instance ('uicc' / 'eSE')
> > +       * appId       : Current appId obtained from 'Principal' obj
> > +       */
> > +      cpmm.sendAsyncMessage("SE:CloseAllByReader", {
> 
> ditto, I think I mentioned this before.

I hope comment#180 , 1.b) clarifies this as well. I understand your point here very well. But lets say we don't do IPC and on closeAll() op in SEReader, we iterate through all its children (SESession) and do session.close() and which in turn tries to close all its children (SEChannel) channel.close().
In all this flow, say if there are two channels to be closed by the reader, say if one is closed properly while other is not (for some reason), wouldn't it be more complicated to track from channel instance to reject closeAll() operation in SEReader(). 
By existing IPC mechanisms, closeAllByReader (or) closeAllBySession() will perform close on all the channels associated with reader (or) session and notifies DOM appropriately. Upon receiving say xxxResolved() event, these instances merely update the state of their children (Ex: this._channel.isClosed = true)
> 
> @@ +156,5 @@
> > +  get isSEPresent() {
> > +    return cpmm.sendSyncMessage("SE:IsSEPresent", {
> > +      type: this.type,
> > +      appId: this._window.document.nodePrincipal.appId
> > +    });
> 
> This shouldn't trigger IPC.
> 
> For the simplest way, this value can be set in getSEReaders();
> and you can update that attribute in follow-up bug.
> 
Ok.
> @@ +159,5 @@
> > +      appId: this._window.document.nodePrincipal.appId
> > +    });
> > +  },
> > +
> > +  receiveMessage: function receiveMessage(aMessage) {
> 
> message.
> or make all arguments in this file prefix with 'a'.
> 
Ok
> This function shouldn't be named 'receiveMessage', as this object doesn't
> process IPC at all,
> it could be named like 'processMessage' to prevent confusion with
> nsIMessageManager.
> 
Ok
> @@ +199,5 @@
> > +
> > +  reader: null,
> > +
> > +  classID: Components.ID("{2b1809f8-17bd-4947-abd7-bdef1498561c}"),
> > +  contractID: "@mozilla.org/secureelement/SESession;1",
> 
> ditto, lower-case.
> 
Ok
> @@ +227,5 @@
> > +      if (this.reader.type === SE.TYPE_UICC) {
> > +        return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
> > +                                                " AID is not specified!");
> > +      }
> > +    } else if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {
> 
> I think I mentioned this before.
> The first 'if' seems not neccesary.
Are you referring to 'if(!aid)' check. If so the 'aid' can be null. If aid is null, in cases of 'uicc' the
request is rejected while for 'eSE' it a perfectly valid usecase. Therefore the checks
> 
> @@ +229,5 @@
> > +                                                " AID is not specified!");
> > +      }
> > +    } else if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {
> > +      return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
> > +            " Invalid AID length - " + aid.length);
> 
> align " with P
> 
Ok
> @@ +232,5 @@
> > +      return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
> > +            " Invalid AID length - " + aid.length);
> > +    } else {
> > +      // copy the aid
> > +      this._aid = aid.subarray(0);
> 
> Where is this._aid being used?
> 
Actually we can remove it.
> @@ +248,5 @@
> > +       * appId       : Current appId obtained from 'Principal' obj
> > +       */
> > +      cpmm.sendAsyncMessage("SE:OpenChannel", {
> > +        resolverId: aResolverId,
> > +        aid: this._aid,
> 
> if this._aid is not used, we could simply supply aid here.
> 
Ok
> @@ +293,5 @@
> > +      channel.isClosed = true;
> > +    }
> > +    this._isClosed = isClosed;
> > +    // Reset the sessionToken
> > +    this._sessionToken = null;
> 
> These attributes (_channels_, _sessionToken) shouldn't be done in setter.
> 
Agreed
> @@ +296,5 @@
> > +    // Reset the sessionToken
> > +    this._sessionToken = null;
> > +  },
> > +
> > +  receiveMessage: function receiveMessage(aMessage) {
> 
> ditto. rename function name and aMessage.
> 
Ok
> @@ +302,5 @@
> > +      case "SE:OpenChannelResolved":
> > +        this._channels.push(aMessage.childContext);
> > +        break;
> > +      case "SE:CloseAllBySessionResolved":
> > +        this.isClosed = true;
> 
> attributes should be set here.
> 
Agreed
> @@ +355,5 @@
> > +    this._sessionToken = sessionToken;
> > +    this._aid = aid;
> > +    // Update 'session' obj
> > +    this.session = sessionCtx;
> > +    this.openResponse = Cu.cloneInto(new Uint8Array(openResponse), win);
> 
> Is 'new Uint8Array' neccesary?
> 
Yes as 'openResponse' is an octet array while 'cloneInto' takes typed array 'Uint8Array' type.
> @@ +375,5 @@
> > +      cla: command.cla,
> > +      ins: command.ins,
> > +      p1: command.p1,
> > +      p2: command.p2,
> > +      data: command.data || null,
> 
> is || null neccesary?
> 
Removed
> @@ +439,5 @@
> > +
> > +  set isClosed(isClosed) {
> > +    this._isClosed = isClosed;
> > +    // Reset the channelToken
> > +    this._channelToken = null;
> 
> ditto
> 
Agreed
> @@ +444,5 @@
> > +  },
> > +
> > +  receiveMessage: function receiveMessage(aMessage) {
> > +    switch (aMessage.name) {
> > +      case "SE:TransmitAPDUResolved": // Do nothing
> 
> nothing?
> 
Removed this statement now.
> From WebIDL it says Promise<SEResponse>
> Where is the response ?
> 
> Oh I found it in line 643.
> So this is totally strange as it seems you process those messages twice.
> 
> The messages should be processed once, and if it has some extra data needs
> to be processed, you should add a method for that.
Ok I will work on this to add a new dedicated method(s). In that case we may not need 'processMessage(...)'
As the patch is being reviewed actively, let's update the target milestone to Jan23.
Flags: needinfo?(whuang)
Whiteboard: [ETA: 12/15]
Target Milestone: 2.2 S2 (19dec) → 2.2 S4 (23jan)
> > 
> Ok. I will try to add more comments and try to explain things clearly. I
> will also try to make it more simple as you said. Do you think some kind of
> face-to-face video call or even an IRC chat session is a good idea ? 
> Because a lot of this is simply lost in translation or typing long
> responses. Or do you think some kind of design doc is useful, I am not sure.
> Please suggest.

Hi Sid, thanks for your hard work. I have verified your patch together with test app, and it looks good. I can't wait to see the patches being landed. :-) 

Regarding to the review process, sometime it's really hard for the patches to get r+ if the reviewer can't fully understand your patches. That's why it's always good to break down the problem and separate the patches into smaller parts. Added the comments in the code is always important to get reviewer's better understanding and make review easier. I think it's mandatory to address 100% of reviewer's comment before submitting the new patch. If you think it's difficult to fix some issues at the moment, maybe we can add the TODO comments in the patch and open the follow-up bugs for that(with reviewer's agreement of course). If you find some review comments are unclear, it's always welcome to discuss with reviewer directly. I think IRC is really good place and tool for discussing these stuff. 

[1] https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style
[2] https://developer.mozilla.org/en-US/docs/Code_Review_FAQ
(In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!) from comment #176)
> Comment on attachment 8544358 [details] [diff] [review]
> Part 1.a: (v1) Add new permission to table - 'secureelement-manage'
> 
> Review of attachment 8544358 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: dom/apps/PermissionsTable.jsm
> @@ +423,5 @@
> >                               additional: ["settings-api"]
> > +                           },
> > +                           "secureelement-manage": {
> > +                             app: DENY_ACTION,
> > +                             privileged: ALLOW_ACTION,
> 
> You also need a trusted entry which you probably want to set to deny. 
> Looking at the context for the diff, it seems like you are on a very old
> tree, please rebase on top of a recent tree in order to avoid excessive
> issues and changes as you get closer to landing.

Due to modem image and QC/Moz Ril limitation, the development process for security element is based on 2.1 branch. I am trying to figure out if we can develop security element based on m-c once bug 1091307 is fixed.

Comment 185

3 years ago
(In reply to Vincent Chang[:vchang] from comment #184)
> (In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!) from
> comment #176)
> > Comment on attachment 8544358 [details] [diff] [review]
> > Part 1.a: (v1) Add new permission to table - 'secureelement-manage'
> > 
> > Review of attachment 8544358 [details] [diff] [review]:
> > -----------------------------------------------------------------
> > 
> > ::: dom/apps/PermissionsTable.jsm
> > @@ +423,5 @@
> > >                               additional: ["settings-api"]
> > > +                           },
> > > +                           "secureelement-manage": {
> > > +                             app: DENY_ACTION,
> > > +                             privileged: ALLOW_ACTION,
> > 
> > You also need a trusted entry which you probably want to set to deny. 
> > Looking at the context for the diff, it seems like you are on a very old
> > tree, please rebase on top of a recent tree in order to avoid excessive
> > issues and changes as you get closer to landing.
> 
> Due to modem image and QC/Moz Ril limitation, the development process for
> security element is based on 2.1 branch. I am trying to figure out if we can
> develop security element based on m-c once bug 1091307 is fixed.
Good point! 
Question: Is it a precondition for landing the SE code into 2.2?
(Assignee)

Updated

3 years ago
Blocks: 1119152
(In reply to Ming Yin from comment #185)
> (In reply to Vincent Chang[:vchang] from comment #184)
> > (In reply to :Ehsan Akhgari (not reading bugmail, needinfo? me!) from
> > comment #176)
> > > Comment on attachment 8544358 [details] [diff] [review]
> > > Part 1.a: (v1) Add new permission to table - 'secureelement-manage'
> > > 
> > > Review of attachment 8544358 [details] [diff] [review]:
> > > -----------------------------------------------------------------
> > > 
> > > ::: dom/apps/PermissionsTable.jsm
> > > @@ +423,5 @@
> > > >                               additional: ["settings-api"]
> > > > +                           },
> > > > +                           "secureelement-manage": {
> > > > +                             app: DENY_ACTION,
> > > > +                             privileged: ALLOW_ACTION,
> > > 
> > > You also need a trusted entry which you probably want to set to deny. 
> > > Looking at the context for the diff, it seems like you are on a very old
> > > tree, please rebase on top of a recent tree in order to avoid excessive
> > > issues and changes as you get closer to landing.
> > 
> > Due to modem image and QC/Moz Ril limitation, the development process for
> > security element is based on 2.1 branch. I am trying to figure out if we can
> > develop security element based on m-c once bug 1091307 is fixed.
> Good point! 
> Question: Is it a precondition for landing the SE code into 22?

Yes, I think it's important for test purpose.
Comment on attachment 8544370 [details] [diff] [review]
Part 5: (v5.1) Add build support for SE feature

Review of attachment 8544370 [details] [diff] [review]:
-----------------------------------------------------------------

what about dom/webidl/moz.build?
Attachment #8544370 - Flags: review?(allstars.chh) → review-
(Assignee)

Comment 188

3 years ago
Created attachment 8548572 [details] [diff] [review]
Part 1 : (v1.10b) Secure Element APIs - Initial Draft
Attachment #8544357 - Attachment is obsolete: true
(Assignee)

Comment 189

3 years ago
(In reply to psiddh: On Leave Jan 14 _ Feb 13 from comment #188)
> Created attachment 8548572 [details] [diff] [review]
> Part 1 : (v1.10b) Secure Element APIs - Initial Draft

Here is the diff : (Change: All the contract ids and lower cased)
https://bugzilla.mozilla.org/attachment.cgi?oldid=8544357&action=interdiff&newid=8548572&headers=1
(Assignee)

Comment 190

3 years ago
Created attachment 8548576 [details] [diff] [review]
Part 2: (v2.4) Secure Element DOM Implementation
Attachment #8544366 - Attachment is obsolete: true
Attachment #8548576 - Flags: review?(allstars.chh)
(Assignee)

Comment 191

3 years ago
Created attachment 8548578 [details] [diff] [review]
Part 3: (v3.5) Secure Element Parent process Implementation. r=yoshi
Attachment #8544369 - Attachment is obsolete: true
Attachment #8548578 - Flags: review?(allstars.chh)
(Assignee)

Comment 192

3 years ago
Created attachment 8548579 [details] [diff] [review]
Part 3a: (v1) Secure Element UiccConnector Implementation. r=yoshi
Attachment #8548579 - Flags: review?(allstars.chh)
(Assignee)

Comment 193

3 years ago
Created attachment 8548580 [details] [diff] [review]
Part 4: (v4.2) Add moz.build for SecureElement files required for part 2 & 3 patches. r=yoshi
Attachment #8544364 - Attachment is obsolete: true
Attachment #8544364 - Flags: review?(allstars.chh)
Attachment #8548580 - Flags: review?(allstars.chh)
(Assignee)

Comment 194

3 years ago
Created attachment 8548583 [details] [diff] [review]
Part 3: (v3.5) Secure Element Parent process Implementation. r=yoshi
Attachment #8548578 - Attachment is obsolete: true
Attachment #8548578 - Flags: review?(allstars.chh)
Attachment #8548583 - Flags: review?(allstars.chh)
(Assignee)

Comment 195

3 years ago
Created attachment 8548584 [details] [diff] [review]
Part 3: (v3.5) Secure Element Parent process Implementation. r=yoshi
Attachment #8548583 - Attachment is obsolete: true
Attachment #8548583 - Flags: review?(allstars.chh)
Attachment #8548584 - Flags: review?(allstars.chh)
(Assignee)

Comment 196

3 years ago
Created attachment 8548586 [details] [diff] [review]
Part 5: (v5.2) Add build support for SE feature
Attachment #8544370 - Attachment is obsolete: true
Attachment #8548586 - Flags: review?(allstars.chh)
(Assignee)

Comment 197

3 years ago
Hi Yoshi,

I think other than the below, rest of the comments are already answered above (or) addressed in the latest patch. Thanks! 


> +      if (((cla & (0xFF & 0x80) === 0)) &&
> +          ((0xFF & (cla & (0xFF & 0x60))) !== (0xFF & 0x20))) {
> +        if (ins === (0xFF & SE.INS_MANAGE_CHANNEL)) {

Since this check is now moved to DOM and since DOM anyway ensures that cla and ins are byte sized (Octet as per webidl),
I have removed '0xFF' and the condition looks much simpler.

> +    if (gMap.isSupportedReaderType(msg.json) &&
>> What would we allow an app getting a reader but no permission for doing anything?
I have removed this code for now. Also I think OpenMobileSpec says something in this order.
I will check the specs again.

> +  void notifyOpenChannelSuccess(in long channel, in DOMString openResponse);
>> DOMString?
nsISecureElementConnector.idl is modelled on nsIIccProvider.idl's interfaces.
As they take DOMString, just retained it as-is

> +    *        callback to notify the result of the operation.
> +    */
> +    void seOpenChannel(in short type,
> +                       in unsigned long clientId,
> +                       in DOMString aid,


>> This should be some TypedArray according to your WebIDL.
same-as-above explanation

> +    * @param callback
> +    *        callback to notify the result of the operation.
> +    */
> +    void seExchangeAPDU(in short type,
> +                        in unsigned long clientId,


>> I am not sure I understand the proposal here.

>> Will RIL, and NFC represent an instance of Connector?
>> Or there's only 1 connector that could connect to RIL and NFC?

>> If it's former 'type' argument could be omited.
>> And if it's latter, it seems to me this interface is an interface of SecureElementManager.

I have removed 'type' args specially as this interface is implemented by a separate file UiccConnector.js

> +
> +this.TYPE_BASIC_CHANNEL = "basic";
> +this.TYPE_LOGICAL_CHANNEL = "logical";
> +
> +this.BASIC_CHANNEL = 0;


>> What's the difference from line 31?
I removed this char constants and moved it to DOM as they are used to set the type of SEChannel instance.
BASIC_CHANNEL is value of basic channel. As per spec, basic channels are always zero irrespective of SE

> @@ +227,5 @@
> > +      if (this.reader.type === SE.TYPE_UICC) {
> > +        return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
> > +                                                " AID is not specified!");
> > +      }
> > +    } else if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {
> 
> I think I mentioned this before.
> The first 'if' seems not neccesary.

Are you referring to 'if(!aid)' check. If so the 'aid' can be null. If aid is null, in cases of 'uicc' the
request is rejected while for 'eSE' it a perfectly valid usecase. Therefore the checks

> Is 'new Uint8Array' neccesary?
> 
I think, Yes as 'openResponse' is an octet array while 'cloneInto' takes typed array 'Uint8Array' type.
Comment on attachment 8548576 [details] [diff] [review]
Part 2: (v2.4) Secure Element DOM Implementation

Review of attachment 8548576 [details] [diff] [review]:
-----------------------------------------------------------------

This looks better.
Please address the comments first.

I'd review this again with the new version of Parent process implementation.

::: dom/secureelement/DOMSecureElement.js
@@ +52,5 @@
> +      aCallback(resolverId);
> +    });
> +  },
> +
> +  createSEPromiseWithCtx: function createSEPromiseWithCtx(ctx, aCallback) {

aCtx

@@ +61,5 @@
> +      });
> +      // Before calling the callback, save the context
> +      this._context[resolverId] = ctx;
> +      aCallback(resolverId);
> +    });

this._context[resolverId] = ctx;
return this.createSEPromise(aCallback);

@@ +64,5 @@
> +      aCallback(resolverId);
> +    });
> +  },
> +
> +  takePromise: function takePromise(resolverId) {

aResolveId

@@ +68,5 @@
> +  takePromise: function takePromise(resolverId) {
> +    let resolver = this.takePromiseResolver(resolverId);
> +    if (!resolver) {
> +      return;
> +    }

put an extra line

@@ +138,5 @@
> +        if (!session.isClosed) {
> +          promises.push(session.closeAll());
> +        }
> +      }
> +      let resolver = PromiseHelpers.takePromiseResolver(aResolverId);

add an extra line.

@@ +143,5 @@
> +      // Wait till all the promises are resolved
> +      Promise.all([promises]).then(function resolved() {
> +        this._sessions = [];
> +        resolver.resolve();
> +      }.bind(this), function rejected(reason) {

move reject to another line.

@@ +217,5 @@
> +      }
> +    } else if (aid.length < SE.MIN_AID_LEN || aid.length > SE.MAX_AID_LEN) {
> +      return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
> +             " Invalid AID length - " + aid.length);
> +    }

What's the first if for?
If aid is null, from your original code it will definitely reject, whether it's for UICC or eSE.
Isn't below code simpler?

let aidLen = aid ? aid.length : 0;
if (aidLen < SE.MIN_AID_LEN || aidLen > SE.MAX_AID_LEN) {
  return ...;
}

@@ +242,5 @@
> +    this._checkClosed();
> +
> +    return PromiseHelpers.createSEPromise((aResolverId) => {
> +      let promises = [];
> +      // Close all children

all children?

@@ +248,5 @@
> +        if (!channel.isClosed) {
> +          promises.push(channel.close());
> +        }
> +      }
> +      let resolver = PromiseHelpers.takePromiseResolver(aResolverId);

put an exra line before let resolve...

@@ +257,5 @@
> +        // Notify parent of this session instance's closure, so that its
> +        // instance entry can be removed from the parent as well.
> +        this._reader.onSessionClose(this.__DOM_IMPL__);
> +        resolver.resolve();
> +      }.bind(this), function rejected(reason) {

ditto.
Attachment #8548576 - Flags: review?(allstars.chh) → feedback+
Comment on attachment 8548584 [details] [diff] [review]
Part 3: (v3.5) Secure Element Parent process Implementation. r=yoshi

Review of attachment 8548584 [details] [diff] [review]:
-----------------------------------------------------------------

r- for
1. there should be an easier data structure for gMap.
2. repeatly/redundant error checks everywhere.
3. doesn't have clear boundary for connector and clientId.
4. many functions have an arg 'callback', but I cannot find where it is provided.

::: dom/secureelement/gonk/SecureElement.js
@@ +92,5 @@
> +    /*
> +    ------------------------------
> +       Structure of 'appInfoMap':
> +    ------------------------------
> +    {[appId :// (key = '1020')

{appId:..

@@ +96,5 @@
> +    {[appId :// (key = '1020')
> +        target         : msg.target
> +        readerTypes    : [] // 'uicc','eSE'
> +        channels : {
> +          [token: // (key = 'aaaaa')

The syntax is wrong.
channels : {
  token: {...}

If I understand this.

@@ +142,5 @@
> +      }
> +    },
> +
> +    // Gets all the channels in an array for the given appId
> +    getAllChannelsByAppId: function(appId) {

That looks strange to me.
You store it as a plain object, but you also use it as an Array.

Can you think of a better way to handling here?

@@ +149,5 @@
> +        debug("Unable to get channels : " + appId);
> +        return [];
> +      }
> +
> +      let channels = appInfo.channels || {};

|| {} is unneccesary.

@@ +176,5 @@
> +      // to the content. Any further 'Channel' related operations by the content
> +      // shall operate using this token.
> +      let token = UUIDGenerator.generateUUID().toString();
> +      // Add the entry
> +      appInfo.channels[token] = { seType: msg.type, aid: msg.aid, channel:  channel };

remove extra space before 2nd channel

@@ +182,5 @@
> +    },
> +
> +    // Remove the given channel entry based on type.
> +    // Note that channel will be unique per type
> +    removeChannel: function(channel, type) {

Why dont you add 'appId' as parameter?

@@ +200,5 @@
> +    },
> +
> +    // Validates the given 'channelToken' by checking if it is a registered one
> +    // for the given (appId, channelToken)
> +    isValidChannelToken: function(data) {

function (appId, channelToken) {
...
}

@@ +212,5 @@
> +          !this.appInfoMap[appId].channels[chToken]) {
> +        return false;
> +      }
> +
> +      return true;

Can these be replaced by simpler code?

@@ +216,5 @@
> +      return true;
> +    },
> +
> +    // Get the 'channel' associated with (appId, channelToken)
> +    getChannel: function(data) {

(appId, channelToken)

@@ +217,5 @@
> +    },
> +
> +    // Get the 'channel' associated with (appId, channelToken)
> +    getChannel: function(data) {
> +      if (!this.isValidChannelToken(data)) {

So far I've already saw a lot of check for validity.
And most of them are checking the same thing again, take this getChannel for example,
The same checks are doing in line 388, 424.

Please move all checks into one place.

@@ +227,5 @@
> +    },
> +
> +    getAppIdByTarget: function(target) {
> +      let appId = Object.keys(this.appInfoMap).find((id) => {
> +        return this.appInfoMap[id] && this.appInfoMap[id].target === target;

Is the first check 'this.appInfoMap[id]' neccesary?

@@ +289,5 @@
> +  },
> +
> +  // Private function used to retreive available readerNames
> +  _getAvailableReaders: function() {
> +    let readerTypes = [];

reader and readerType should be different.

Make your code clear.

@@ +299,5 @@
> +    readerTypes.push(SE.TYPE_UICC);
> +    return readerTypes;
> +  },
> +
> +  _closeAllChannelsByAppId: function(appId, type, callback) {

who provides this callback?

@@ +342,5 @@
> +  },
> +
> +  // Following functions are handlers for requests from content
> +
> +  handleOpenChannel: function(msg, callback) {

who will provide the callback?

@@ +355,5 @@
> +    }
> +
> +    // TODO: Bug 1118098  - Integrate with ACE module
> +    let connector = getConnector(msg.type);
> +    connector.openChannel(PREFERRED_UICC_CLIENTID,

UICC_CLIENTID should be used inside UiccConnector since it's a UICC-specific thing.

@@ +476,5 @@
> +    if (!appId) {
> +      return;
> +    }
> +    this._closeAllChannelsByAppId(appId, SE.TYPE_UICC, null);
> +    gMap.unregisterSecureElementTarget(target);

this function should take appId as parameter.

@@ +485,5 @@
> +   */
> +
> +  receiveMessage: function(msg) {
> +    debug("Received '" + msg.name + "' message from content process" +
> +          ": " + JSON.stringify(msg.data));

add if (DEBUG) for the JSON.stringify.

@@ +498,5 @@
> +    if (SE_IPC_SECUREELEMENT_MSG_NAMES.indexOf(msg.name) != -1) {
> +      if (!msg.target.assertPermission("secureelement-manage")) {
> +        debug("SecureElement message " + msg.name + " from a content process " +
> +              "with no 'secureelement-manage' privileges.");
> +        throw new Error("Don't know about this message: " + msg.name);

The error message is not correct.
Attachment #8548584 - Flags: review?(allstars.chh) → review-