OpenSSL unable to verify data: error:0906D06C:PEM routines:PEM_read_bio:no start line in Box API - box-api

Im getting the above error when sending the following body to the Box OAuth /token operation:
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&client_id=.............&client_secret=..........&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im81NGFtcGR6In0=.eyJpc3MiOiIyOHRhZmZ0ejhlenhncnI3aTBocmZnMGlteTc2MjRuMyIsInN1YiI6IjU0MjA5MSIsImJveF9zdWJfdHlwZSI6ImVudGVycHJpc2UiLCJhdWQiOiJodHRwczovL2FwaS5ib3guY29tL29hdXRoMi90b2tlbiIsImp0aSI6IjE0NDYyMzA3MTgxMjM0NTYiLCJleHAiOjE0NDYyMzA3NjgsImlhdCI6MTQ0NjIzMDcxOH0=.ANwpzohhFyUmPMw1wh6kM8xzqsUanS3UIdEPN40hvpVDmzI9wS0fTpmxWvudGPPXXmeE0Cr+frbMx+R9V9DvzfJsGv2+mu1bqwsjHwPkOy06IigAvgiJPPFt9CuIdmY/H6pGtDpODfeau77KrT0OJhpQX9He4xy0maS26D7yc/5F3fyxZXHdG/XzTpx88xTpg2HbEJ5ImeZjxkFf6ZH4Un0ZY9TJ3TSEITTcqRxhAUN2qAttnX8H5jmKWyTE5U78+f1LzQz1lPjnQsj/BSRCrF2jkf7N0LfJwq3U1BXNBWiEZRW8wqvaTvZLpiODDsl6VuG/xs1m549wGVwyXCglJQ==
Now the JWT, of the assertion parameter, verifies correctly at jwt.io, and the Public key defined to Box verifies in the Box UI as well at jwt.io.
This indicates to me that what I'm sending is correct.
However Box has an issue..... any help would be very greatly received!

The problem seems to be in the public and private key generated using openssl in a DOS command prompt.
You can follow the instructions in this link:
https://box-content.readme.io/docs/app-auth
First of all, you have to download Cygwin tool: http://www.cygwin.com/
Then, in the Cygwin console you can launch the following commands:
For the private key
openssl genrsa -aes256 -out private_key.pem 2048
For the public key
openssl rsa -pubout -in private_key.pem -out public_key.pem
Be sure to include the full header and footer: '-----BEGIN PUBLIC KEY-----' AND '-----END PUBLIC KEY-----'
Once you've generated a public key, you will need to add it in your app's configuration.
When finished you'll get a Public Key ID.
You should be able to connect with your keys using the Box API.
var privateKey = File.ReadAllText("private_key.pem");
var boxConfig = new BoxConfig(CLIENT_ID, CLIENT_SECRET, ENTERPRISE_ID, privateKey, JWT_PRIVATE_KEY_PASSWORD, JWT_PUBLIC_KEY_ID);
var boxJWT = new BoxJWTAuth(boxConfig);
var adminToken = boxJWT.AdminToken();
Console.WriteLine("Admin Token: " + adminToken);
I hope this will help you

Right... this is extremely annoying!
Despite having created correct JWT's for other Public API's, and having the Header and body of the claim, and the signature verified by jwt.io, THE ONLY WAY to get box to accept my JWT was to use the JOSE4J utilities that the Box SDK uses.
This is really poor BOX - lift your game, and support JWT that are valid, not just the proprietary ones created by the JOSE4J classes!!!

The JWT in the example in the question that is the value of the assertion parameter appears to have its parts encoded using regular base64 encoding rather than base64url encoding prescribed by JWT/JWS. Many/most base64 implementations are very liberal in decoding and will happily accept base64 or base64url interchangeably. I'd guess that is why, despite that JWT not technically adhering to the specifications, it verifies okay when used directly at something like jwt.io. However, it might cause problems if not properly encoded when sent in the body of the HTTP request, which is expected to be application/x-www-form-urlencoded. The '+', for example, will decode to a space which will be ignored by many base64 decoders. The description in the error you're seeing doesn't seem to line up with that being the problem but it will corrupt the data and be a problem at some point (unless maybe you are url encoding the parameter values and just showing them unencoded in the question). Using base64url rather than base64 will mean that the value of the assertion parameter doesn't need to be url encoded and won't get messed up during url decoding. And base64url will be compliant with JWT. At least it would let you rule out some potential problems.

I had exactly the same problem, with the same error message from Box and the JWT verifying correctly in jwt.io.
It turns out that the problem was in Base64 vs Base64Url encoding. As Brian pointed, jwt.io can use both Base64 and Base64Url encoding, but Box requires Base64Url. The framework I am using uses Base64 by default and this was the problem and after forcing Base64Url on all parts of the JWT assertion, Box login succeeded.

Related

JWT decoding say invalid signature even on providing correct "signing" key

JWT tokenization is driving me crazy or I am using it wrong.
To test out and start with "jjwt", i am creating a simple jwt token, below is the code.
static String createSimpleJWT() {
String id, issuer, subject;
id="id";
issuer="issuer";
subject="subject";
//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder().setId(id)
.setSubject(subject)
.setIssuer(issuer)
.signWith(SignatureAlgorithm.HS256, "signingKey"); //plz note signing key on this line
return builder.compact();
}
The jwt token is
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJpZCIsInN1YiI6InN1YmplY3QiLCJpc3MiOiJpc3N1ZXIifQ._7QGamE-HvREDMJIgbfKEIRv76ZaxwIx2t3RaViSYzth4
As intended, on subsequent executions also I get the same JWT.
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJpZCIsInN1YiI6InN1YmplY3QiLCJpc3MiOiJpc3N1ZXIifQ._7QGE-HvREDMJIgbfKEIRv76ZaxwIx2t3RaViSYzth4
I am decoding it using jwt.io to test -
but am suprised to see that the jwt token is flaged with Invalid Signature inspite of providing the correct signing key in the decode section.
Here is jwt.io screenshot - jwt.io-invalidsignature
Any pointers... where it's getting messed.
This post is different from what's asked earlier where the users forgot or were not aware about providing signing key to jwt.io
PHP JWT Token Invalid Signature
JWT Token Invalid Signature
Your issue is similar to this https://stackoverflow.com/a/38269014/6371459.
It is due to .signWith(SignatureAlgorithm.HS256, "secret"). It is implemented by DefaultJwtBuilder class
public JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey)
This method assumes that you are providing a key in base64 and secret is not base64. When the method decodes from base64 to byte[] the java converter used by jjwt provides a representation of the string secr which is different to the JavaScript decoder used at jwt.io
JWTBuilder.signWith requires a base64 encoded key, but you are providing a plain text, so:
Insert "signingK" and check "secret base64 encoded" in jwt.io
Provide a base64 encoded password
--
String signingKeyB64= Base64.getEncoder().encodeToString("signingKey".getBytes("utf-8"));
JwtBuilder builder = Jwts.builder().setId(id)
.setSubject(subject)
.setIssuer(issuer)
.signWith(SignatureAlgorithm.HS256, signingKeyB64);
I recommend to generate a random password instead of using a fixed string
Key key = MacProvider.generateKey();
String signingKeyB64 = Base64.getEncoder().encodeToString(key.getEncoded());
I had nearly the same issue with this JWT lib so I changed it to another one. Don't know why this happens. My Application is used to authenticate against a third party system.
Try this Lib an check it again, perhaps this helps you:
https://github.com/auth0/java-jwt

Google cloud KMS: encryption works but decryption fails

I am trying to decrypt a token using the google KMS tool.
Running it locally, for some reason, encryption seems to work but not decryption.
I am running the following code:
import base64
import googleapiclient.discovery
kms_client = googleapiclient.discovery.build('cloudkms', 'v1')
crypto_keys = kms_client.projects().locations().keyRings().cryptoKeys()
name = "projects/my-project/locations/my-loc/keyRings/my-kr/cryptoKeys/my-key"
request = crypto_keys.decrypt(name=name, body={'ciphertext': base64.b64encode("my text").decode('ascii')})
response = request.execute()
The last line returns a 400 error:
HttpError: <HttpError 400 when requesting https://cloudkms.g[...]ion:decrypt?alt=json
returned "Decryption failed: verify that 'name' refers to the correct CryptoKey.">
The name, however, actually seems to be correct.
Surprisingly enough, replacing the call to decrypt by encrypt, I obtain a valid output.
Am I missing an obvious mistake, or should I just open a issue on the project's github ?
EDIT:
I was trying to decrypt plain text, which of course does not make much sense (but the error message misled me somewhat).
Make sure that the ciphertext you're trying to decrypt was encrypted using the same key. In case you used another key to encrypt, KMS tells you that it could not find the key while actually the key was found but couldn't be used to decrypt the cipher.
I think the error message is "a bit" misleading.

in SAS: create a JSON Web Signature for Google API

I am using SAS 9.4. I want to write a JSON Web Signature ("JWS") to complete my JSON Web Token ("JWT") - (I already have the header and claims encoded and tested). I would like to make API calls to Google. My problem is that I am not certain how to create the JWS. Per all the docs and tutorial web sites I have researched the syntax to create the signature is (pseudo-code):
encodedContent = base64UrlEncode(header) + "." + base64UrlEncode(payload);
signature = hashHmacSHA256($encodedContent);
and/or
var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload);
HMACSHA256(encodedString, 'secret');
etc.
I have been attempting to create the JWS using SAS PROC GROOVY code found here:
https://gist.github.com/FriedEgg/79ad315afa1b315e8ac3
...and other places.
Google's doc (https://developers.google.com/identity/protocols/OAuth2ServiceAccount) states:
"Sign the UTF-8 representation of the input ('{Base64url encoded header}.{Base64url encoded claim set}') using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) with the private key obtained from the Google Developers Console. The output will be a byte array."
However, I am confused about what key to use (or whether I should be using a key) as some sites (example above) just suggest hashing the encoded header+claims while others suggest hashing using a "secret key" while say "private key" - and the github page (URL above) just uses a "key".
I am also confused about sha1 vs. sha256. The Google docs sate sha256 but some have suggested sha1 in this Stack Overflow thread: questions/18362327/creating-digital-signature-usining-sas-for-google-api-geocode
Again, I have verified my header and claims SAS code work using:
jwt dot io
and
kjur dot github dot io/jsjws /tool_jwt.html
Since SAS supports Groovy (PROC GROOVY) I assume that I can write my JWT successfully using java code but I have not yet been able to replicate any JWT in my SAS code using examples found on the sites I have mentioned above and others.
Has anyone ever done this before (using SAS to connect to Google APIs using JWT)?
Any help is appreciated!

%40 is not getting decoded to # in Jmeter

I'm trying Jmeter tool for load testing where i'm feeding the data through a csv file which has all the emails and passwords for login request. But while passing the parameter, Jmeter is encoding '#' sign with '%40' and if i put %40 in place of # in my csv, its not getting decoded to # in Jmeter. For other special characters, the encoding and decoding is happening properly. Please help.
It should be totally expected.
If you're logging in via GET request %40 is correct way of encoding # symbol.
If you're sending a POST request, JMeter should automatically send # symbol (at least my JMeter 2.10 does)
You might wish to try one of following:
Add View Results Tree listener, switch to HTTP tab and see what's actually being sent.
Make sure that Encode? box is unchecked for email parameter
Explicitly tell JMeter to decode email via __urldecode() function
Use a Beanshell Pre Processor to properly encode/decode your email
import java.net.URLDecoder;
import java.net.URLEncoder;
String email = "someone#example.com";
String encoded = URLEncoder.encode(email, "UTF-8");
String decoded = URLDecoder.decode(encoded, "UTF-8");
This is coming when we do via Parameters,
If we do using "Body Data" that would work fine.
I used this way.
{"password":"${password}","emailId":"${emailId}"}
For the HTTP Request, Change the Client implementation to Java
Select the Advanced tab from the HTTP Request
In Client Implementation > Choose Java in Implementation

Using Json string in the Http Header

Recently I run into some weird issue with http header usage ( Adding multiple custom http request headers mystery) To avoid the problem at that time, I have put the fields into json string and add that json string into header instead of adding those fields into separate http headers.
For example, instead of
request.addHeader("UserName", mUserName);
request.addHeader("AuthToken", mAuthorizationToken);
request.addHeader("clientId","android_client");
I have created a json string and add it to the single header
String jsonStr="{\"UserName\":\"myname\",\"AuthToken\":\"123456\",\"clientId\":\"android_client\"}";
request.addHeader("JSonStr",jsonStr);
Since I am new to writing Rest and dealing with the Http stuff, I don't know if my usage is proper or not. I would appreciate some insight into this.
Some links
http://lists.w3.org/Archives/Public/ietf-http-wg/2011OctDec/0133.html
Yes, you may use JSON in HTTP headers, given some limitations.
According to the HTTP spec, your header field-body may only contain visible ASCII characters, tab, and space.
Since many JSON encoders (e.g. json_encode in PHP) will encode invisible or non-ASCII characters (e.g. "é" becomes "\u00e9"), you often don't need to worry about this.
Check the docs for your particular encoder or test it, though, because JSON strings technically allow most any Unicode character. For example, in JavaScript JSON.stringify() does not escape multibyte Unicode, by default. However, you can easily modify it to do so, e.g.
var charsToEncode = /[\u007f-\uffff]/g;
function http_header_safe_json(v) {
return JSON.stringify(v).replace(charsToEncode,
function(c) {
return '\\u'+('000'+c.charCodeAt(0).toString(16)).slice(-4);
}
);
}
Source
Alternatively, you can do as #rocketspacer suggested and base64-encode the JSON before inserting it into the header field (e.g. how JWT does it). This makes the JSON unreadable (by humans) in the header, but ensures that it will conform to the spec.
Worth noting, the original ARPA spec (RFC 822) has a special description of this exact use case, and the spirit of this echoes in later specs such as RFC 7230:
Certain field-bodies of headers may be interpreted according to an
internal syntax that some systems may wish to parse.
Also, RFC 822 and RFC 7230 explicitly give no length constraints:
HTTP does not place a predefined limit on the length of each header field or on the length of the header section as a whole, as described in Section 2.5.
Base64encode it before sending. Just like how JSON Web Token do it.
Here's a NodeJs Example:
const myJsonStr = JSON.stringify(myData);
const headerFriendlyStr = Buffer.from(myJsonStr, 'utf8').toString('base64');
res.addHeader('foo', headerFriendlyStr);
Decode it when you need reading:
const myBase64Str = req.headers['foo'];
const myJsonStr = Buffer.from(myBase64Str, 'base64').toString('utf8');
const myData = JSON.parse(myJsonStr);
Generally speaking you do not send data in the header for a REST API. If you need to send a lot of data it best to use an HTTP POST and send the data in the body of the request. But it looks like you are trying to pass credentials in the header, which some REST API's do use. Here is an example for passing the credentials in a REST API for a service called SMSIfied, which allows you to send SMS text message via the Internet. This example is using basic authentication, which is a a common technique for REST API's. But you will need to use SSL with this technique to make it secure. Here is an example on how to implement basic authentication with WCF and REST.
From what I understand using a json string in the header option is not as much of an abuse of usage as using http DELETE for http GET, thus there has even been proposal to use json in http header. Of course more thorough insights are still welcome and the accepted answer is still to be given.
In the design-first age the OpenAPI specification gives another perspective:
an HTTP header parameter may be an object,
e.g. object X-MyHeader is
{"role": "admin", "firstName": "Alex"}
however, within the HTTP request/response the value is serialized, e.g.
X-MyHeader: role=admin,firstName=Alex