Example #1
0
  /**
   * Create a new user ID token from the provided JSON object. The associated master token must be
   * provided to verify the user ID token.
   *
   * @param ctx MSL context.
   * @param userIdTokenJO user ID token JSON object.
   * @param masterToken the master token.
   * @throws MslEncodingException if there is an error parsing the JSON, the token data is missing
   *     or invalid, or the signature is invalid.
   * @throws MslCryptoException if there is an error verifying the token data.
   * @throws MslException if the user ID token master token serial number does not match the master
   *     token serial number, or the expiration timestamp occurs before the renewal window, or the
   *     user data is missing or invalid, or the user ID token master token serial number is out of
   *     range, or the user ID token serial number is out of range.
   */
  public UserIdToken(
      final MslContext ctx, final JSONObject userIdTokenJO, final MasterToken masterToken)
      throws MslEncodingException, MslCryptoException, MslException {
    this.ctx = ctx;

    // Grab the crypto context.
    final ICryptoContext cryptoContext = ctx.getMslCryptoContext();

    // Verify the JSON representation.
    try {
      try {
        tokendata = Base64.decode(userIdTokenJO.getString(KEY_TOKENDATA));
      } catch (final IllegalArgumentException e) {
        throw new MslEncodingException(
                MslError.USERIDTOKEN_TOKENDATA_INVALID,
                "useridtoken " + userIdTokenJO.toString(),
                e)
            .setMasterToken(masterToken);
      }
      if (tokendata == null || tokendata.length == 0)
        throw new MslEncodingException(
                MslError.USERIDTOKEN_TOKENDATA_MISSING, "useridtoken " + userIdTokenJO.toString())
            .setMasterToken(masterToken);
      try {
        signature = Base64.decode(userIdTokenJO.getString(KEY_SIGNATURE));
      } catch (final IllegalArgumentException e) {
        throw new MslEncodingException(
                MslError.USERIDTOKEN_SIGNATURE_INVALID,
                "useridtoken " + userIdTokenJO.toString(),
                e)
            .setMasterToken(masterToken);
      }
      verified = cryptoContext.verify(tokendata, signature);
    } catch (final JSONException e) {
      throw new MslEncodingException(
              MslError.JSON_PARSE_ERROR, "useridtoken " + userIdTokenJO.toString(), e)
          .setMasterToken(masterToken);
    }

    // Pull the token data.
    final String tokenDataJson = new String(tokendata, MslConstants.DEFAULT_CHARSET);
    try {
      final JSONObject tokenDataJO = new JSONObject(tokenDataJson);
      renewalWindow = tokenDataJO.getLong(KEY_RENEWAL_WINDOW);
      expiration = tokenDataJO.getLong(KEY_EXPIRATION);
      if (expiration < renewalWindow)
        throw new MslException(
                MslError.USERIDTOKEN_EXPIRES_BEFORE_RENEWAL, "usertokendata " + tokenDataJson)
            .setMasterToken(masterToken);
      mtSerialNumber = tokenDataJO.getLong(KEY_MASTER_TOKEN_SERIAL_NUMBER);
      if (mtSerialNumber < 0 || mtSerialNumber > MslConstants.MAX_LONG_VALUE)
        throw new MslException(
                MslError.USERIDTOKEN_MASTERTOKEN_SERIAL_NUMBER_OUT_OF_RANGE,
                "usertokendata " + tokenDataJson)
            .setMasterToken(masterToken);
      serialNumber = tokenDataJO.getLong(KEY_SERIAL_NUMBER);
      if (serialNumber < 0 || serialNumber > MslConstants.MAX_LONG_VALUE)
        throw new MslException(
                MslError.USERIDTOKEN_SERIAL_NUMBER_OUT_OF_RANGE, "usertokendata " + tokenDataJson)
            .setMasterToken(masterToken);
      final byte[] ciphertext;
      try {
        ciphertext = Base64.decode(tokenDataJO.getString(KEY_USERDATA));
      } catch (final IllegalArgumentException e) {
        throw new MslException(
                MslError.USERIDTOKEN_USERDATA_INVALID, tokenDataJO.getString(KEY_USERDATA))
            .setMasterToken(masterToken);
      }
      if (ciphertext == null || ciphertext.length == 0)
        throw new MslException(
                MslError.USERIDTOKEN_USERDATA_MISSING, tokenDataJO.getString(KEY_USERDATA))
            .setMasterToken(masterToken);
      userdata = (verified) ? cryptoContext.decrypt(ciphertext) : null;
    } catch (final JSONException e) {
      throw new MslEncodingException(
              MslError.USERIDTOKEN_TOKENDATA_PARSE_ERROR, "usertokendata " + tokenDataJson, e)
          .setMasterToken(masterToken);
    } catch (final MslCryptoException e) {
      e.setMasterToken(masterToken);
      throw e;
    }

    // Pull the user data.
    if (userdata != null) {
      final String userDataJson = new String(userdata, MslConstants.DEFAULT_CHARSET);
      try {
        final JSONObject userDataJO = new JSONObject(userDataJson);
        issuerData =
            (userDataJO.has(KEY_ISSUER_DATA)) ? userDataJO.getJSONObject(KEY_ISSUER_DATA) : null;
        final String identity = userDataJO.getString(KEY_IDENTITY);
        if (identity == null || identity.length() == 0)
          throw new MslException(MslError.USERIDTOKEN_IDENTITY_INVALID, "userdata " + userDataJson)
              .setMasterToken(masterToken);
        final TokenFactory factory = ctx.getTokenFactory();
        user = factory.createUser(ctx, identity);
        if (user == null)
          throw new MslInternalException(
              "TokenFactory.createUser() returned null in violation of the interface contract.");
      } catch (final JSONException e) {
        throw new MslEncodingException(
                MslError.USERIDTOKEN_USERDATA_PARSE_ERROR, "userdata " + userDataJson, e)
            .setMasterToken(masterToken);
      }
    } else {
      issuerData = null;
      user = null;
    }

    // Verify serial numbers.
    if (masterToken == null || this.mtSerialNumber != masterToken.getSerialNumber())
      throw new MslException(
              MslError.USERIDTOKEN_MASTERTOKEN_MISMATCH,
              "uit mtserialnumber " + this.mtSerialNumber + "; mt " + masterToken)
          .setMasterToken(masterToken);
  }
Example #2
0
  /**
   * Create a new user ID token with the specified user.
   *
   * @param ctx MSL context.
   * @param renewalWindow the renewal window.
   * @param expiration the expiration.
   * @param masterToken the master token.
   * @param serialNumber the user ID token serial number.
   * @param issuerData the issuer data. May be null.
   * @param user the MSL user.
   * @throws MslEncodingException if there is an error encoding the JSON data.
   * @throws MslCryptoException if there is an error encrypting or signing the token data.
   */
  public UserIdToken(
      final MslContext ctx,
      final Date renewalWindow,
      final Date expiration,
      final MasterToken masterToken,
      final long serialNumber,
      final JSONObject issuerData,
      final MslUser user)
      throws MslEncodingException, MslCryptoException {
    // The expiration must appear after the renewal window.
    if (expiration.before(renewalWindow))
      throw new MslInternalException(
          "Cannot construct a user ID token that expires before its renewal window opens.");
    // A master token must be provided.
    if (masterToken == null)
      throw new MslInternalException("Cannot construct a user ID token without a master token.");
    // The serial number must be within range.
    if (serialNumber < 0 || serialNumber > MslConstants.MAX_LONG_VALUE)
      throw new MslInternalException(
          "Serial number " + serialNumber + " is outside the valid range.");

    this.ctx = ctx;
    this.renewalWindow = renewalWindow.getTime() / MILLISECONDS_PER_SECOND;
    this.expiration = expiration.getTime() / MILLISECONDS_PER_SECOND;
    this.mtSerialNumber = masterToken.getSerialNumber();
    this.serialNumber = serialNumber;
    this.issuerData = issuerData;
    this.user = user;

    // Construct the user data.
    final JSONObject userData = new JSONObject();
    try {
      if (this.issuerData != null) userData.put(KEY_ISSUER_DATA, this.issuerData);
      userData.put(KEY_IDENTITY, user.getEncoded());
      this.userdata = userData.toString().getBytes(MslConstants.DEFAULT_CHARSET);
    } catch (final JSONException e) {
      throw new MslEncodingException(MslError.JSON_ENCODE_ERROR, "userdata", e);
    }

    try {
      // Encrypt the user data.
      final ICryptoContext cryptoContext = ctx.getMslCryptoContext();
      final byte[] ciphertext = cryptoContext.encrypt(this.userdata);

      // Construct the token data.
      try {
        final JSONObject tokenDataJO = new JSONObject();
        tokenDataJO.put(KEY_RENEWAL_WINDOW, this.renewalWindow);
        tokenDataJO.put(KEY_EXPIRATION, this.expiration);
        tokenDataJO.put(KEY_MASTER_TOKEN_SERIAL_NUMBER, this.mtSerialNumber);
        tokenDataJO.put(KEY_SERIAL_NUMBER, this.serialNumber);
        tokenDataJO.put(KEY_USERDATA, Base64.encode(ciphertext));
        this.tokendata = tokenDataJO.toString().getBytes(MslConstants.DEFAULT_CHARSET);
      } catch (final JSONException e) {
        throw new MslEncodingException(MslError.JSON_ENCODE_ERROR, "usertokendata", e)
            .setMasterToken(masterToken);
      }

      // Sign the token data.
      this.signature = cryptoContext.sign(this.tokendata);
      this.verified = true;
    } catch (final MslCryptoException e) {
      e.setMasterToken(masterToken);
      throw e;
    }
  }