I'm a novice C ++ programmer (I'm still in college, so I suppose I'm a pretty novice programmer in general), and I'm trying to create a JWT in C ++. I can generate and encode the header and payload, but the signature I generate with the openssl hmac library seems invalid when I check it on jwt.io. I have a feeling that this is due to some nuanced error that I just don't see. If you find my mistake, I will be very grateful. If you also have suggestions for improving my code as a whole, that will also be appreciated. Note. I need to use openssl and boost for json.
**** **** UPDATE
I found that additional new lines are being added, which caused authentication errors. I am currently calling str.erase to remove them, but if someone can tell me where they are going, I would appreciate it, so I can avoid having to manipulate the string
char* Auth::genJWT() { ptree pt; std::stringstream jwt; //Make and encode header pt.put("typ","JWT"); pt.put("alg","HS256"); std::ostringstream buf; write_json(buf, pt, false); std::string header = buf.str(); jwt << base64_encode((unsigned char*)header.c_str(), (int) header.length()); //clear buffer pt.clear(); buf.clear(); buf.str(""); //make pay load pt.put("org_guid", Config::organization_guid); pt.put("agent_guid", Config::agent_guid); write_json(buf, pt, false); std::string payload = buf.str(); jwt << '.' << base64_encode((unsigned char*)payload.c_str(), (int) payload.length()); //sign data std::string signed_data = signToken(jwt.str()); jwt << '.' << base64_encode((unsigned char*) signed_data.c_str(), (int) signed_data.length()); //jwt made std::cout << "JWT Token: " << jwt.str() << std::endl; //Note I am testing by copying the token into an online debugger //returning "" is not my bug return ""; }
This is the method that I use to denote a token
std::string Auth::signToken(std::string to_sign) { //std::string key = Config::secret; std::string key = "foo"; unsigned int len = 32; unsigned char signed_data[32]; HMAC_CTX ctx; HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, &key[0], (int) key.length(), EVP_sha256(), NULL); HMAC_Update(&ctx, (unsigned char*)&to_sign[0], to_sign.length()); HMAC_Final(&ctx, signed_data, &len); HMAC_CTX_cleanup(&ctx); std::stringstream ss; ss << std::setfill('0'); for(unsigned int i = 0; i < len; i++) { ss << signed_data[i]; } return (ss.str()); }
This is how I encode data in base64Url
std::string Auth::base64_encode(const unsigned char* input, int length) { BIO *bmem, *b64; BUF_MEM *bptr; b64 = BIO_new(BIO_f_base64()); bmem = BIO_new(BIO_s_mem()); b64 = BIO_push(b64, bmem); BIO_write(b64, input, length); BIO_flush(b64); BIO_get_mem_ptr(b64, &bptr); std::stringstream ss; //make URL safe for(unsigned int i = 0; i < bptr->length - 1; i++) { switch(bptr->data[i]) { case '+': ss << '_'; break; case '/': ss << '-'; break; case '=': //don't add in padding break; default: ss << bptr->data[i]; break; } } BIO_free_all(b64); return (ss.str()); }